"no use strict";
;(function(window) {
    if (typeof window.window != "undefined" && window.document)
        return;
    if (window.require && window.define)
        return;

    if (!window.console) {
        window.console = function() {
            var msgs = Array.prototype.slice.call(arguments, 0);
            postMessage({type: "log", data: msgs});
        };
        window.console.error =
            window.console.warn =
                window.console.log =
                    window.console.trace = window.console;
    }
    window.window = window;
    window.ace = window;

    window.onerror = function(message, file, line, col, err) {
        postMessage({type: "error", data: {
            message: message,
            data: err.data,
            file: file,
            line: line,
            col: col,
            stack: err.stack
        }});
    };

    window.normalizeModule = function(parentId, moduleName) {
        // normalize plugin requires
        if (moduleName.indexOf("!") !== -1) {
            var chunks = moduleName.split("!");
            return window.normalizeModule(parentId, chunks[0]) + "!" + window.normalizeModule(parentId, chunks[1]);
        }
        // normalize relative requires
        if (moduleName.charAt(0) == ".") {
            var base = parentId.split("/").slice(0, -1).join("/");
            moduleName = (base ? base + "/" : "") + moduleName;

            while (moduleName.indexOf(".") !== -1 && previous != moduleName) {
                var previous = moduleName;
                moduleName = moduleName.replace(/^\.\//, "").replace(/\/\.\//, "/").replace(/[^\/]+\/\.\.\//, "");
            }
        }

        return moduleName;
    };

    window.require = function require(parentId, id) {
        if (!id) {
            id = parentId;
            parentId = null;
        }
        if (!id.charAt)
            throw new Error("worker.js require() accepts only (parentId, id) as arguments");

        id = window.normalizeModule(parentId, id);

        var module = window.require.modules[id];
        if (module) {
            if (!module.initialized) {
                module.initialized = true;
                module.exports = module.factory().exports;
            }
            return module.exports;
        }

        if (!window.require.tlns)
            return console.log("unable to load " + id);

        var path = resolveModuleId(id, window.require.tlns);
        if (path.slice(-3) != ".js") path += ".js";

        window.require.id = id;
        window.require.modules[id] = {}; // prevent infinite loop on broken modules
        importScripts(path);
        return window.require(parentId, id);
    };
    function resolveModuleId(id, paths) {
        var testPath = id, tail = "";
        while (testPath) {
            var alias = paths[testPath];
            if (typeof alias == "string") {
                return alias + tail;
            } else if (alias) {
                return  alias.location.replace(/\/*$/, "/") + (tail || alias.main || alias.name);
            } else if (alias === false) {
                return "";
            }
            var i = testPath.lastIndexOf("/");
            if (i === -1) break;
            tail = testPath.substr(i) + tail;
            testPath = testPath.slice(0, i);
        }
        return id;
    }
    window.require.modules = {};
    window.require.tlns = {};

    window.define = function(id, deps, factory) {
        if (arguments.length == 2) {
            factory = deps;
            if (typeof id != "string") {
                deps = id;
                id = window.require.id;
            }
        } else if (arguments.length == 1) {
            factory = id;
            deps = [];
            id = window.require.id;
        }

        if (typeof factory != "function") {
            window.require.modules[id] = {
                exports: factory,
                initialized: true
            };
            return;
        }

        if (!deps.length)
        // If there is no dependencies, we inject "require", "exports" and
        // "module" as dependencies, to provide CommonJS compatibility.
            deps = ["require", "exports", "module"];

        var req = function(childId) {
            return window.require(id, childId);
        };

        window.require.modules[id] = {
            exports: {},
            factory: function() {
                var module = this;
                var returnExports = factory.apply(this, deps.map(function(dep) {
                    switch (dep) {
                        // Because "require", "exports" and "module" aren't actual
                        // dependencies, we must handle them seperately.
                        case "require": return req;
                        case "exports": return module.exports;
                        case "module":  return module;
                        // But for all other dependencies, we can just go ahead and
                        // require them.
                        default:        return req(dep);
                    }
                }));
                if (returnExports)
                    module.exports = returnExports;
                return module;
            }
        };
    };
    window.define.amd = {};
    require.tlns = {};
    window.initBaseUrls  = function initBaseUrls(topLevelNamespaces) {
        for (var i in topLevelNamespaces)
            require.tlns[i] = topLevelNamespaces[i];
    };

    window.initSender = function initSender() {

        var EventEmitter = window.require("ace/lib/event_emitter").EventEmitter;
        var oop = window.require("ace/lib/oop");

        var Sender = function() {};

        (function() {

            oop.implement(this, EventEmitter);

            this.callback = function(data, callbackId) {
                postMessage({
                    type: "call",
                    id: callbackId,
                    data: data
                });
            };

            this.emit = function(name, data) {
                postMessage({
                    type: "event",
                    name: name,
                    data: data
                });
            };

        }).call(Sender.prototype);

        return new Sender();
    };

    var main = window.main = null;
    var sender = window.sender = null;

    window.onmessage = function(e) {
        var msg = e.data;
        if (msg.event && sender) {
            sender._signal(msg.event, msg.data);
        }
        else if (msg.command) {
            if (main[msg.command])
                main[msg.command].apply(main, msg.args);
            else if (window[msg.command])
                window[msg.command].apply(window, msg.args);
            else
                throw new Error("Unknown command:" + msg.command);
        }
        else if (msg.init) {
            window.initBaseUrls(msg.tlns);
            require("ace/lib/es5-shim");
            sender = window.sender = window.initSender();
            var clazz = require(msg.module)[msg.classname];
            main = window.main = new clazz(sender);
        }
    };
})(this);

ace.define("ace/lib/oop",["require","exports","module"], function(require, exports, module) {
    "use strict";

    exports.inherits = function(ctor, superCtor) {
        ctor.super_ = superCtor;
        ctor.prototype = Object.create(superCtor.prototype, {
            constructor: {
                value: ctor,
                enumerable: false,
                writable: true,
                configurable: true
            }
        });
    };

    exports.mixin = function(obj, mixin) {
        for (var key in mixin) {
            obj[key] = mixin[key];
        }
        return obj;
    };

    exports.implement = function(proto, mixin) {
        exports.mixin(proto, mixin);
    };

});

ace.define("ace/range",["require","exports","module"], function(require, exports, module) {
    "use strict";
    var comparePoints = function(p1, p2) {
        return p1.row - p2.row || p1.column - p2.column;
    };
    var Range = function(startRow, startColumn, endRow, endColumn) {
        this.start = {
            row: startRow,
            column: startColumn
        };

        this.end = {
            row: endRow,
            column: endColumn
        };
    };

    (function() {
        this.isEqual = function(range) {
            return this.start.row === range.start.row &&
                this.end.row === range.end.row &&
                this.start.column === range.start.column &&
                this.end.column === range.end.column;
        };
        this.toString = function() {
            return ("Range: [" + this.start.row + "/" + this.start.column +
            "] -> [" + this.end.row + "/" + this.end.column + "]");
        };

        this.contains = function(row, column) {
            return this.compare(row, column) == 0;
        };
        this.compareRange = function(range) {
            var cmp,
                end = range.end,
                start = range.start;

            cmp = this.compare(end.row, end.column);
            if (cmp == 1) {
                cmp = this.compare(start.row, start.column);
                if (cmp == 1) {
                    return 2;
                } else if (cmp == 0) {
                    return 1;
                } else {
                    return 0;
                }
            } else if (cmp == -1) {
                return -2;
            } else {
                cmp = this.compare(start.row, start.column);
                if (cmp == -1) {
                    return -1;
                } else if (cmp == 1) {
                    return 42;
                } else {
                    return 0;
                }
            }
        };
        this.comparePoint = function(p) {
            return this.compare(p.row, p.column);
        };
        this.containsRange = function(range) {
            return this.comparePoint(range.start) == 0 && this.comparePoint(range.end) == 0;
        };
        this.intersects = function(range) {
            var cmp = this.compareRange(range);
            return (cmp == -1 || cmp == 0 || cmp == 1);
        };
        this.isEnd = function(row, column) {
            return this.end.row == row && this.end.column == column;
        };
        this.isStart = function(row, column) {
            return this.start.row == row && this.start.column == column;
        };
        this.setStart = function(row, column) {
            if (typeof row == "object") {
                this.start.column = row.column;
                this.start.row = row.row;
            } else {
                this.start.row = row;
                this.start.column = column;
            }
        };
        this.setEnd = function(row, column) {
            if (typeof row == "object") {
                this.end.column = row.column;
                this.end.row = row.row;
            } else {
                this.end.row = row;
                this.end.column = column;
            }
        };
        this.inside = function(row, column) {
            if (this.compare(row, column) == 0) {
                if (this.isEnd(row, column) || this.isStart(row, column)) {
                    return false;
                } else {
                    return true;
                }
            }
            return false;
        };
        this.insideStart = function(row, column) {
            if (this.compare(row, column) == 0) {
                if (this.isEnd(row, column)) {
                    return false;
                } else {
                    return true;
                }
            }
            return false;
        };
        this.insideEnd = function(row, column) {
            if (this.compare(row, column) == 0) {
                if (this.isStart(row, column)) {
                    return false;
                } else {
                    return true;
                }
            }
            return false;
        };
        this.compare = function(row, column) {
            if (!this.isMultiLine()) {
                if (row === this.start.row) {
                    return column < this.start.column ? -1 : (column > this.end.column ? 1 : 0);
                }
            }

            if (row < this.start.row)
                return -1;

            if (row > this.end.row)
                return 1;

            if (this.start.row === row)
                return column >= this.start.column ? 0 : -1;

            if (this.end.row === row)
                return column <= this.end.column ? 0 : 1;

            return 0;
        };
        this.compareStart = function(row, column) {
            if (this.start.row == row && this.start.column == column) {
                return -1;
            } else {
                return this.compare(row, column);
            }
        };
        this.compareEnd = function(row, column) {
            if (this.end.row == row && this.end.column == column) {
                return 1;
            } else {
                return this.compare(row, column);
            }
        };
        this.compareInside = function(row, column) {
            if (this.end.row == row && this.end.column == column) {
                return 1;
            } else if (this.start.row == row && this.start.column == column) {
                return -1;
            } else {
                return this.compare(row, column);
            }
        };
        this.clipRows = function(firstRow, lastRow) {
            if (this.end.row > lastRow)
                var end = {row: lastRow + 1, column: 0};
            else if (this.end.row < firstRow)
                var end = {row: firstRow, column: 0};

            if (this.start.row > lastRow)
                var start = {row: lastRow + 1, column: 0};
            else if (this.start.row < firstRow)
                var start = {row: firstRow, column: 0};

            return Range.fromPoints(start || this.start, end || this.end);
        };
        this.extend = function(row, column) {
            var cmp = this.compare(row, column);

            if (cmp == 0)
                return this;
            else if (cmp == -1)
                var start = {row: row, column: column};
            else
                var end = {row: row, column: column};

            return Range.fromPoints(start || this.start, end || this.end);
        };

        this.isEmpty = function() {
            return (this.start.row === this.end.row && this.start.column === this.end.column);
        };
        this.isMultiLine = function() {
            return (this.start.row !== this.end.row);
        };
        this.clone = function() {
            return Range.fromPoints(this.start, this.end);
        };
        this.collapseRows = function() {
            if (this.end.column == 0)
                return new Range(this.start.row, 0, Math.max(this.start.row, this.end.row-1), 0)
            else
                return new Range(this.start.row, 0, this.end.row, 0)
        };
        this.toScreenRange = function(session) {
            var screenPosStart = session.documentToScreenPosition(this.start);
            var screenPosEnd = session.documentToScreenPosition(this.end);

            return new Range(
                screenPosStart.row, screenPosStart.column,
                screenPosEnd.row, screenPosEnd.column
            );
        };
        this.moveBy = function(row, column) {
            this.start.row += row;
            this.start.column += column;
            this.end.row += row;
            this.end.column += column;
        };

    }).call(Range.prototype);
    Range.fromPoints = function(start, end) {
        return new Range(start.row, start.column, end.row, end.column);
    };
    Range.comparePoints = comparePoints;

    Range.comparePoints = function(p1, p2) {
        return p1.row - p2.row || p1.column - p2.column;
    };


    exports.Range = Range;
});

ace.define("ace/apply_delta",["require","exports","module"], function(require, exports, module) {
    "use strict";

    function throwDeltaError(delta, errorText){
        console.log("Invalid Delta:", delta);
        throw "Invalid Delta: " + errorText;
    }

    function positionInDocument(docLines, position) {
        return position.row    >= 0 && position.row    <  docLines.length &&
            position.column >= 0 && position.column <= docLines[position.row].length;
    }

    function validateDelta(docLines, delta) {
        if (delta.action != "insert" && delta.action != "remove")
            throwDeltaError(delta, "delta.action must be 'insert' or 'remove'");
        if (!(delta.lines instanceof Array))
            throwDeltaError(delta, "delta.lines must be an Array");
        if (!delta.start || !delta.end)
            throwDeltaError(delta, "delta.start/end must be an present");
        var start = delta.start;
        if (!positionInDocument(docLines, delta.start))
            throwDeltaError(delta, "delta.start must be contained in document");
        var end = delta.end;
        if (delta.action == "remove" && !positionInDocument(docLines, end))
            throwDeltaError(delta, "delta.end must contained in document for 'remove' actions");
        var numRangeRows = end.row - start.row;
        var numRangeLastLineChars = (end.column - (numRangeRows == 0 ? start.column : 0));
        if (numRangeRows != delta.lines.length - 1 || delta.lines[numRangeRows].length != numRangeLastLineChars)
            throwDeltaError(delta, "delta.range must match delta lines");
    }

    exports.applyDelta = function(docLines, delta, doNotValidate) {

        var row = delta.start.row;
        var startColumn = delta.start.column;
        var line = docLines[row] || "";
        switch (delta.action) {
            case "insert":
                var lines = delta.lines;
                if (lines.length === 1) {
                    docLines[row] = line.substring(0, startColumn) + delta.lines[0] + line.substring(startColumn);
                } else {
                    var args = [row, 1].concat(delta.lines);
                    docLines.splice.apply(docLines, args);
                    docLines[row] = line.substring(0, startColumn) + docLines[row];
                    docLines[row + delta.lines.length - 1] += line.substring(startColumn);
                }
                break;
            case "remove":
                var endColumn = delta.end.column;
                var endRow = delta.end.row;
                if (row === endRow) {
                    docLines[row] = line.substring(0, startColumn) + line.substring(endColumn);
                } else {
                    docLines.splice(
                        row, endRow - row + 1,
                        line.substring(0, startColumn) + docLines[endRow].substring(endColumn)
                    );
                }
                break;
        }
    }
});

ace.define("ace/lib/event_emitter",["require","exports","module"], function(require, exports, module) {
    "use strict";

    var EventEmitter = {};
    var stopPropagation = function() { this.propagationStopped = true; };
    var preventDefault = function() { this.defaultPrevented = true; };

    EventEmitter._emit =
        EventEmitter._dispatchEvent = function(eventName, e) {
            this._eventRegistry || (this._eventRegistry = {});
            this._defaultHandlers || (this._defaultHandlers = {});

            var listeners = this._eventRegistry[eventName] || [];
            var defaultHandler = this._defaultHandlers[eventName];
            if (!listeners.length && !defaultHandler)
                return;

            if (typeof e != "object" || !e)
                e = {};

            if (!e.type)
                e.type = eventName;
            if (!e.stopPropagation)
                e.stopPropagation = stopPropagation;
            if (!e.preventDefault)
                e.preventDefault = preventDefault;

            listeners = listeners.slice();
            for (var i=0; i<listeners.length; i++) {
                listeners[i](e, this);
                if (e.propagationStopped)
                    break;
            }

            if (defaultHandler && !e.defaultPrevented)
                return defaultHandler(e, this);
        };


    EventEmitter._signal = function(eventName, e) {
        var listeners = (this._eventRegistry || {})[eventName];
        if (!listeners)
            return;
        listeners = listeners.slice();
        for (var i=0; i<listeners.length; i++)
            listeners[i](e, this);
    };

    EventEmitter.once = function(eventName, callback) {
        var _self = this;
        callback && this.addEventListener(eventName, function newCallback() {
            _self.removeEventListener(eventName, newCallback);
            callback.apply(null, arguments);
        });
    };


    EventEmitter.setDefaultHandler = function(eventName, callback) {
        var handlers = this._defaultHandlers
        if (!handlers)
            handlers = this._defaultHandlers = {_disabled_: {}};

        if (handlers[eventName]) {
            var old = handlers[eventName];
            var disabled = handlers._disabled_[eventName];
            if (!disabled)
                handlers._disabled_[eventName] = disabled = [];
            disabled.push(old);
            var i = disabled.indexOf(callback);
            if (i != -1)
                disabled.splice(i, 1);
        }
        handlers[eventName] = callback;
    };
    EventEmitter.removeDefaultHandler = function(eventName, callback) {
        var handlers = this._defaultHandlers
        if (!handlers)
            return;
        var disabled = handlers._disabled_[eventName];

        if (handlers[eventName] == callback) {
            var old = handlers[eventName];
            if (disabled)
                this.setDefaultHandler(eventName, disabled.pop());
        } else if (disabled) {
            var i = disabled.indexOf(callback);
            if (i != -1)
                disabled.splice(i, 1);
        }
    };

    EventEmitter.on =
        EventEmitter.addEventListener = function(eventName, callback, capturing) {
            this._eventRegistry = this._eventRegistry || {};

            var listeners = this._eventRegistry[eventName];
            if (!listeners)
                listeners = this._eventRegistry[eventName] = [];

            if (listeners.indexOf(callback) == -1)
                listeners[capturing ? "unshift" : "push"](callback);
            return callback;
        };

    EventEmitter.off =
        EventEmitter.removeListener =
            EventEmitter.removeEventListener = function(eventName, callback) {
                this._eventRegistry = this._eventRegistry || {};

                var listeners = this._eventRegistry[eventName];
                if (!listeners)
                    return;

                var index = listeners.indexOf(callback);
                if (index !== -1)
                    listeners.splice(index, 1);
            };

    EventEmitter.removeAllListeners = function(eventName) {
        if (this._eventRegistry) this._eventRegistry[eventName] = [];
    };

    exports.EventEmitter = EventEmitter;

});

ace.define("ace/anchor",["require","exports","module","ace/lib/oop","ace/lib/event_emitter"], function(require, exports, module) {
    "use strict";

    var oop = require("./lib/oop");
    var EventEmitter = require("./lib/event_emitter").EventEmitter;

    var Anchor = exports.Anchor = function(doc, row, column) {
        this.$onChange = this.onChange.bind(this);
        this.attach(doc);

        if (typeof column == "undefined")
            this.setPosition(row.row, row.column);
        else
            this.setPosition(row, column);
    };

    (function() {

        oop.implement(this, EventEmitter);
        this.getPosition = function() {
            return this.$clipPositionToDocument(this.row, this.column);
        };
        this.getDocument = function() {
            return this.document;
        };
        this.$insertRight = false;
        this.onChange = function(delta) {
            if (delta.start.row == delta.end.row && delta.start.row != this.row)
                return;

            if (delta.start.row > this.row)
                return;

            var point = $getTransformedPoint(delta, {row: this.row, column: this.column}, this.$insertRight);
            this.setPosition(point.row, point.column, true);
        };

        function $pointsInOrder(point1, point2, equalPointsInOrder) {
            var bColIsAfter = equalPointsInOrder ? point1.column <= point2.column : point1.column < point2.column;
            return (point1.row < point2.row) || (point1.row == point2.row && bColIsAfter);
        }

        function $getTransformedPoint(delta, point, moveIfEqual) {
            var deltaIsInsert = delta.action == "insert";
            var deltaRowShift = (deltaIsInsert ? 1 : -1) * (delta.end.row    - delta.start.row);
            var deltaColShift = (deltaIsInsert ? 1 : -1) * (delta.end.column - delta.start.column);
            var deltaStart = delta.start;
            var deltaEnd = deltaIsInsert ? deltaStart : delta.end; // Collapse insert range.
            if ($pointsInOrder(point, deltaStart, moveIfEqual)) {
                return {
                    row: point.row,
                    column: point.column
                };
            }
            if ($pointsInOrder(deltaEnd, point, !moveIfEqual)) {
                return {
                    row: point.row + deltaRowShift,
                    column: point.column + (point.row == deltaEnd.row ? deltaColShift : 0)
                };
            }

            return {
                row: deltaStart.row,
                column: deltaStart.column
            };
        }
        this.setPosition = function(row, column, noClip) {
            var pos;
            if (noClip) {
                pos = {
                    row: row,
                    column: column
                };
            } else {
                pos = this.$clipPositionToDocument(row, column);
            }

            if (this.row == pos.row && this.column == pos.column)
                return;

            var old = {
                row: this.row,
                column: this.column
            };

            this.row = pos.row;
            this.column = pos.column;
            this._signal("change", {
                old: old,
                value: pos
            });
        };
        this.detach = function() {
            this.document.removeEventListener("change", this.$onChange);
        };
        this.attach = function(doc) {
            this.document = doc || this.document;
            this.document.on("change", this.$onChange);
        };
        this.$clipPositionToDocument = function(row, column) {
            var pos = {};

            if (row >= this.document.getLength()) {
                pos.row = Math.max(0, this.document.getLength() - 1);
                pos.column = this.document.getLine(pos.row).length;
            }
            else if (row < 0) {
                pos.row = 0;
                pos.column = 0;
            }
            else {
                pos.row = row;
                pos.column = Math.min(this.document.getLine(pos.row).length, Math.max(0, column));
            }

            if (column < 0)
                pos.column = 0;

            return pos;
        };

    }).call(Anchor.prototype);

});

ace.define("ace/document",["require","exports","module","ace/lib/oop","ace/apply_delta","ace/lib/event_emitter","ace/range","ace/anchor"], function(require, exports, module) {
    "use strict";

    var oop = require("./lib/oop");
    var applyDelta = require("./apply_delta").applyDelta;
    var EventEmitter = require("./lib/event_emitter").EventEmitter;
    var Range = require("./range").Range;
    var Anchor = require("./anchor").Anchor;

    var Document = function(textOrLines) {
        this.$lines = [""];
        if (textOrLines.length === 0) {
            this.$lines = [""];
        } else if (Array.isArray(textOrLines)) {
            this.insertMergedLines({row: 0, column: 0}, textOrLines);
        } else {
            this.insert({row: 0, column:0}, textOrLines);
        }
    };

    (function() {

        oop.implement(this, EventEmitter);
        this.setValue = function(text) {
            var len = this.getLength() - 1;
            this.remove(new Range(0, 0, len, this.getLine(len).length));
            this.insert({row: 0, column: 0}, text);
        };
        this.getValue = function() {
            return this.getAllLines().join(this.getNewLineCharacter());
        };
        this.createAnchor = function(row, column) {
            return new Anchor(this, row, column);
        };
        if ("aaa".split(/a/).length === 0) {
            this.$split = function(text) {
                return text.replace(/\r\n|\r/g, "\n").split("\n");
            };
        } else {
            this.$split = function(text) {
                return text.split(/\r\n|\r|\n/);
            };
        }


        this.$detectNewLine = function(text) {
            var match = text.match(/^.*?(\r\n|\r|\n)/m);
            this.$autoNewLine = match ? match[1] : "\n";
            this._signal("changeNewLineMode");
        };
        this.getNewLineCharacter = function() {
            switch (this.$newLineMode) {
                case "windows":
                    return "\r\n";
                case "unix":
                    return "\n";
                default:
                    return this.$autoNewLine || "\n";
            }
        };

        this.$autoNewLine = "";
        this.$newLineMode = "auto";
        this.setNewLineMode = function(newLineMode) {
            if (this.$newLineMode === newLineMode)
                return;

            this.$newLineMode = newLineMode;
            this._signal("changeNewLineMode");
        };
        this.getNewLineMode = function() {
            return this.$newLineMode;
        };
        this.isNewLine = function(text) {
            return (text == "\r\n" || text == "\r" || text == "\n");
        };
        this.getLine = function(row) {
            return this.$lines[row] || "";
        };
        this.getLines = function(firstRow, lastRow) {
            return this.$lines.slice(firstRow, lastRow + 1);
        };
        this.getAllLines = function() {
            return this.getLines(0, this.getLength());
        };
        this.getLength = function() {
            return this.$lines.length;
        };
        this.getTextRange = function(range) {
            return this.getLinesForRange(range).join(this.getNewLineCharacter());
        };
        this.getLinesForRange = function(range) {
            var lines;
            if (range.start.row === range.end.row) {
                lines = [this.getLine(range.start.row).substring(range.start.column, range.end.column)];
            } else {
                lines = this.getLines(range.start.row, range.end.row);
                lines[0] = (lines[0] || "").substring(range.start.column);
                var l = lines.length - 1;
                if (range.end.row - range.start.row == l)
                    lines[l] = lines[l].substring(0, range.end.column);
            }
            return lines;
        };
        this.insertLines = function(row, lines) {
            console.warn("Use of document.insertLines is deprecated. Use the insertFullLines method instead.");
            return this.insertFullLines(row, lines);
        };
        this.removeLines = function(firstRow, lastRow) {
            console.warn("Use of document.removeLines is deprecated. Use the removeFullLines method instead.");
            return this.removeFullLines(firstRow, lastRow);
        };
        this.insertNewLine = function(position) {
            console.warn("Use of document.insertNewLine is deprecated. Use insertMergedLines(position, ['', '']) instead.");
            return this.insertMergedLines(position, ["", ""]);
        };
        this.insert = function(position, text) {
            if (this.getLength() <= 1)
                this.$detectNewLine(text);

            return this.insertMergedLines(position, this.$split(text));
        };
        this.insertInLine = function(position, text) {
            var start = this.clippedPos(position.row, position.column);
            var end = this.pos(position.row, position.column + text.length);

            this.applyDelta({
                start: start,
                end: end,
                action: "insert",
                lines: [text]
            }, true);

            return this.clonePos(end);
        };

        this.clippedPos = function(row, column) {
            var length = this.getLength();
            if (row === undefined) {
                row = length;
            } else if (row < 0) {
                row = 0;
            } else if (row >= length) {
                row = length - 1;
                column = undefined;
            }
            var line = this.getLine(row);
            if (column == undefined)
                column = line.length;
            column = Math.min(Math.max(column, 0), line.length);
            return {row: row, column: column};
        };

        this.clonePos = function(pos) {
            return {row: pos.row, column: pos.column};
        };

        this.pos = function(row, column) {
            return {row: row, column: column};
        };

        this.$clipPosition = function(position) {
            var length = this.getLength();
            if (position.row >= length) {
                position.row = Math.max(0, length - 1);
                position.column = this.getLine(length - 1).length;
            } else {
                position.row = Math.max(0, position.row);
                position.column = Math.min(Math.max(position.column, 0), this.getLine(position.row).length);
            }
            return position;
        };
        this.insertFullLines = function(row, lines) {
            row = Math.min(Math.max(row, 0), this.getLength());
            var column = 0;
            if (row < this.getLength()) {
                lines = lines.concat([""]);
                column = 0;
            } else {
                lines = [""].concat(lines);
                row--;
                column = this.$lines[row].length;
            }
            this.insertMergedLines({row: row, column: column}, lines);
        };
        this.insertMergedLines = function(position, lines) {
            var start = this.clippedPos(position.row, position.column);
            var end = {
                row: start.row + lines.length - 1,
                column: (lines.length == 1 ? start.column : 0) + lines[lines.length - 1].length
            };

            this.applyDelta({
                start: start,
                end: end,
                action: "insert",
                lines: lines
            });

            return this.clonePos(end);
        };
        this.remove = function(range) {
            var start = this.clippedPos(range.start.row, range.start.column);
            var end = this.clippedPos(range.end.row, range.end.column);
            this.applyDelta({
                start: start,
                end: end,
                action: "remove",
                lines: this.getLinesForRange({start: start, end: end})
            });
            return this.clonePos(start);
        };
        this.removeInLine = function(row, startColumn, endColumn) {
            var start = this.clippedPos(row, startColumn);
            var end = this.clippedPos(row, endColumn);

            this.applyDelta({
                start: start,
                end: end,
                action: "remove",
                lines: this.getLinesForRange({start: start, end: end})
            }, true);

            return this.clonePos(start);
        };
        this.removeFullLines = function(firstRow, lastRow) {
            firstRow = Math.min(Math.max(0, firstRow), this.getLength() - 1);
            lastRow  = Math.min(Math.max(0, lastRow ), this.getLength() - 1);
            var deleteFirstNewLine = lastRow == this.getLength() - 1 && firstRow > 0;
            var deleteLastNewLine  = lastRow  < this.getLength() - 1;
            var startRow = ( deleteFirstNewLine ? firstRow - 1                  : firstRow                    );
            var startCol = ( deleteFirstNewLine ? this.getLine(startRow).length : 0                           );
            var endRow   = ( deleteLastNewLine  ? lastRow + 1                   : lastRow                     );
            var endCol   = ( deleteLastNewLine  ? 0                             : this.getLine(endRow).length );
            var range = new Range(startRow, startCol, endRow, endCol);
            var deletedLines = this.$lines.slice(firstRow, lastRow + 1);

            this.applyDelta({
                start: range.start,
                end: range.end,
                action: "remove",
                lines: this.getLinesForRange(range)
            });
            return deletedLines;
        };
        this.removeNewLine = function(row) {
            if (row < this.getLength() - 1 && row >= 0) {
                this.applyDelta({
                    start: this.pos(row, this.getLine(row).length),
                    end: this.pos(row + 1, 0),
                    action: "remove",
                    lines: ["", ""]
                });
            }
        };
        this.replace = function(range, text) {
            if (!(range instanceof Range))
                range = Range.fromPoints(range.start, range.end);
            if (text.length === 0 && range.isEmpty())
                return range.start;
            if (text == this.getTextRange(range))
                return range.end;

            this.remove(range);
            var end;
            if (text) {
                end = this.insert(range.start, text);
            }
            else {
                end = range.start;
            }

            return end;
        };
        this.applyDeltas = function(deltas) {
            for (var i=0; i<deltas.length; i++) {
                this.applyDelta(deltas[i]);
            }
        };
        this.revertDeltas = function(deltas) {
            for (var i=deltas.length-1; i>=0; i--) {
                this.revertDelta(deltas[i]);
            }
        };
        this.applyDelta = function(delta, doNotValidate) {
            var isInsert = delta.action == "insert";
            if (isInsert ? delta.lines.length <= 1 && !delta.lines[0]
                    : !Range.comparePoints(delta.start, delta.end)) {
                return;
            }

            if (isInsert && delta.lines.length > 20000)
                this.$splitAndapplyLargeDelta(delta, 20000);
            applyDelta(this.$lines, delta, doNotValidate);
            this._signal("change", delta);
        };

        this.$splitAndapplyLargeDelta = function(delta, MAX) {
            var lines = delta.lines;
            var l = lines.length;
            var row = delta.start.row;
            var column = delta.start.column;
            var from = 0, to = 0;
            do {
                from = to;
                to += MAX - 1;
                var chunk = lines.slice(from, to);
                if (to > l) {
                    delta.lines = chunk;
                    delta.start.row = row + from;
                    delta.start.column = column;
                    break;
                }
                chunk.push("");
                this.applyDelta({
                    start: this.pos(row + from, column),
                    end: this.pos(row + to, column = 0),
                    action: delta.action,
                    lines: chunk
                }, true);
            } while(true);
        };
        this.revertDelta = function(delta) {
            this.applyDelta({
                start: this.clonePos(delta.start),
                end: this.clonePos(delta.end),
                action: (delta.action == "insert" ? "remove" : "insert"),
                lines: delta.lines.slice()
            });
        };
        this.indexToPosition = function(index, startRow) {
            var lines = this.$lines || this.getAllLines();
            var newlineLength = this.getNewLineCharacter().length;
            for (var i = startRow || 0, l = lines.length; i < l; i++) {
                index -= lines[i].length + newlineLength;
                if (index < 0)
                    return {row: i, column: index + lines[i].length + newlineLength};
            }
            return {row: l-1, column: lines[l-1].length};
        };
        this.positionToIndex = function(pos, startRow) {
            var lines = this.$lines || this.getAllLines();
            var newlineLength = this.getNewLineCharacter().length;
            var index = 0;
            var row = Math.min(pos.row, lines.length);
            for (var i = startRow || 0; i < row; ++i)
                index += lines[i].length + newlineLength;

            return index + pos.column;
        };

    }).call(Document.prototype);

    exports.Document = Document;
});

ace.define("ace/lib/lang",["require","exports","module"], function(require, exports, module) {
    "use strict";

    exports.last = function(a) {
        return a[a.length - 1];
    };

    exports.stringReverse = function(string) {
        return string.split("").reverse().join("");
    };

    exports.stringRepeat = function (string, count) {
        var result = '';
        while (count > 0) {
            if (count & 1)
                result += string;

            if (count >>= 1)
                string += string;
        }
        return result;
    };

    var trimBeginRegexp = /^\s\s*/;
    var trimEndRegexp = /\s\s*$/;

    exports.stringTrimLeft = function (string) {
        return string.replace(trimBeginRegexp, '');
    };

    exports.stringTrimRight = function (string) {
        return string.replace(trimEndRegexp, '');
    };

    exports.copyObject = function(obj) {
        var copy = {};
        for (var key in obj) {
            copy[key] = obj[key];
        }
        return copy;
    };

    exports.copyArray = function(array){
        var copy = [];
        for (var i=0, l=array.length; i<l; i++) {
            if (array[i] && typeof array[i] == "object")
                copy[i] = this.copyObject(array[i]);
            else
                copy[i] = array[i];
        }
        return copy;
    };

    exports.deepCopy = function deepCopy(obj) {
        if (typeof obj !== "object" || !obj)
            return obj;
        var copy;
        if (Array.isArray(obj)) {
            copy = [];
            for (var key = 0; key < obj.length; key++) {
                copy[key] = deepCopy(obj[key]);
            }
            return copy;
        }
        if (Object.prototype.toString.call(obj) !== "[object Object]")
            return obj;

        copy = {};
        for (var key in obj)
            copy[key] = deepCopy(obj[key]);
        return copy;
    };

    exports.arrayToMap = function(arr) {
        var map = {};
        for (var i=0; i<arr.length; i++) {
            map[arr[i]] = 1;
        }
        return map;

    };

    exports.createMap = function(props) {
        var map = Object.create(null);
        for (var i in props) {
            map[i] = props[i];
        }
        return map;
    };
    exports.arrayRemove = function(array, value) {
        for (var i = 0; i <= array.length; i++) {
            if (value === array[i]) {
                array.splice(i, 1);
            }
        }
    };

    exports.escapeRegExp = function(str) {
        return str.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1');
    };

    exports.escapeHTML = function(str) {
        return str.replace(/&/g, "&#38;").replace(/"/g, "&#34;").replace(/'/g, "&#39;").replace(/</g, "&#60;");
    };

    exports.getMatchOffsets = function(string, regExp) {
        var matches = [];

        string.replace(regExp, function(str) {
            matches.push({
                offset: arguments[arguments.length-2],
                length: str.length
            });
        });

        return matches;
    };
    exports.deferredCall = function(fcn) {
        var timer = null;
        var callback = function() {
            timer = null;
            fcn();
        };

        var deferred = function(timeout) {
            deferred.cancel();
            timer = setTimeout(callback, timeout || 0);
            return deferred;
        };

        deferred.schedule = deferred;

        deferred.call = function() {
            this.cancel();
            fcn();
            return deferred;
        };

        deferred.cancel = function() {
            clearTimeout(timer);
            timer = null;
            return deferred;
        };

        deferred.isPending = function() {
            return timer;
        };

        return deferred;
    };


    exports.delayedCall = function(fcn, defaultTimeout) {
        var timer = null;
        var callback = function() {
            timer = null;
            fcn();
        };

        var _self = function(timeout) {
            if (timer == null)
                timer = setTimeout(callback, timeout || defaultTimeout);
        };

        _self.delay = function(timeout) {
            timer && clearTimeout(timer);
            timer = setTimeout(callback, timeout || defaultTimeout);
        };
        _self.schedule = _self;

        _self.call = function() {
            this.cancel();
            fcn();
        };

        _self.cancel = function() {
            timer && clearTimeout(timer);
            timer = null;
        };

        _self.isPending = function() {
            return timer;
        };

        return _self;
    };
});

ace.define("ace/worker/mirror",["require","exports","module","ace/range","ace/document","ace/lib/lang"], function(require, exports, module) {
    "use strict";

    var Range = require("../range").Range;
    var Document = require("../document").Document;
    var lang = require("../lib/lang");

    var Mirror = exports.Mirror = function(sender) {
        this.sender = sender;
        var doc = this.doc = new Document("");

        var deferredUpdate = this.deferredUpdate = lang.delayedCall(this.onUpdate.bind(this));

        var _self = this;
        sender.on("change", function(e) {
            var data = e.data;
            if (data[0].start) {
                doc.applyDeltas(data);
            } else {
                for (var i = 0; i < data.length; i += 2) {
                    if (Array.isArray(data[i+1])) {
                        var d = {action: "insert", start: data[i], lines: data[i+1]};
                    } else {
                        var d = {action: "remove", start: data[i], end: data[i+1]};
                    }
                    doc.applyDelta(d, true);
                }
            }
            if (_self.$timeout)
                return deferredUpdate.schedule(_self.$timeout);
            _self.onUpdate();
        });
    };

    (function() {

        this.$timeout = 500;

        this.setTimeout = function(timeout) {
            this.$timeout = timeout;
        };

        this.setValue = function(value) {
            this.doc.setValue(value);
            this.deferredUpdate.schedule(this.$timeout);
        };

        this.getValue = function(callbackId) {
            this.sender.callback(this.doc.getValue(), callbackId);
        };

        this.onUpdate = function() {
        };

        this.isPending = function() {
            return this.deferredUpdate.isPending();
        };

    }).call(Mirror.prototype);

});

ace.define("ace/mode/javascript/jshint",["require","exports","module"], function(require, exports, module) {
    module.exports = (function outer (modules, cache, entry) {
        var previousRequire = typeof require == "function" && require;
        function newRequire(name, jumped){
            if(!cache[name]) {
                if(!modules[name]) {
                    var currentRequire = typeof require == "function" && require;
                    if (!jumped && currentRequire) return currentRequire(name, true);
                    if (previousRequire) return previousRequire(name, true);
                    var err = new Error('Cannot find module \'' + name + '\'');
                    err.code = 'MODULE_NOT_FOUND';
                    throw err;
                }
                var m = cache[name] = {exports:{}};
                modules[name][0].call(m.exports, function(x){
                    var id = modules[name][1][x];
                    return newRequire(id ? id : x);
                },m,m.exports,outer,modules,cache,entry);
            }
            return cache[name].exports;
        }
        for(var i=0;i<entry.length;i++) newRequire(entry[i]);
        return newRequire(entry[0]);
    })
    ({"/node_modules/browserify/node_modules/events/events.js":[function(_dereq_,module,exports){

        function EventEmitter() {
            this._events = this._events || {};
            this._maxListeners = this._maxListeners || undefined;
        }
        module.exports = EventEmitter;
        EventEmitter.EventEmitter = EventEmitter;

        EventEmitter.prototype._events = undefined;
        EventEmitter.prototype._maxListeners = undefined;
        EventEmitter.defaultMaxListeners = 10;
        EventEmitter.prototype.setMaxListeners = function(n) {
            if (!isNumber(n) || n < 0 || isNaN(n))
                throw TypeError('n must be a positive number');
            this._maxListeners = n;
            return this;
        };

        EventEmitter.prototype.emit = function(type) {
            var er, handler, len, args, i, listeners;

            if (!this._events)
                this._events = {};
            if (type === 'error') {
                if (!this._events.error ||
                    (isObject(this._events.error) && !this._events.error.length)) {
                    er = arguments[1];
                    if (er instanceof Error) {
                        throw er; // Unhandled 'error' event
                    }
                    throw TypeError('Uncaught, unspecified "error" event.');
                }
            }

            handler = this._events[type];

            if (isUndefined(handler))
                return false;

            if (isFunction(handler)) {
                switch (arguments.length) {
                    case 1:
                        handler.call(this);
                        break;
                    case 2:
                        handler.call(this, arguments[1]);
                        break;
                    case 3:
                        handler.call(this, arguments[1], arguments[2]);
                        break;
                    default:
                        len = arguments.length;
                        args = new Array(len - 1);
                        for (i = 1; i < len; i++)
                            args[i - 1] = arguments[i];
                        handler.apply(this, args);
                }
            } else if (isObject(handler)) {
                len = arguments.length;
                args = new Array(len - 1);
                for (i = 1; i < len; i++)
                    args[i - 1] = arguments[i];

                listeners = handler.slice();
                len = listeners.length;
                for (i = 0; i < len; i++)
                    listeners[i].apply(this, args);
            }

            return true;
        };

        EventEmitter.prototype.addListener = function(type, listener) {
            var m;

            if (!isFunction(listener))
                throw TypeError('listener must be a function');

            if (!this._events)
                this._events = {};
            if (this._events.newListener)
                this.emit('newListener', type,
                    isFunction(listener.listener) ?
                        listener.listener : listener);

            if (!this._events[type])
                this._events[type] = listener;
            else if (isObject(this._events[type]))
                this._events[type].push(listener);
            else
                this._events[type] = [this._events[type], listener];
            if (isObject(this._events[type]) && !this._events[type].warned) {
                var m;
                if (!isUndefined(this._maxListeners)) {
                    m = this._maxListeners;
                } else {
                    m = EventEmitter.defaultMaxListeners;
                }

                if (m && m > 0 && this._events[type].length > m) {
                    this._events[type].warned = true;
                    console.error('(node) warning: possible EventEmitter memory ' +
                        'leak detected. %d listeners added. ' +
                        'Use emitter.setMaxListeners() to increase limit.',
                        this._events[type].length);
                    if (typeof console.trace === 'function') {
                        console.trace();
                    }
                }
            }

            return this;
        };

        EventEmitter.prototype.on = EventEmitter.prototype.addListener;

        EventEmitter.prototype.once = function(type, listener) {
            if (!isFunction(listener))
                throw TypeError('listener must be a function');

            var fired = false;

            function g() {
                this.removeListener(type, g);

                if (!fired) {
                    fired = true;
                    listener.apply(this, arguments);
                }
            }

            g.listener = listener;
            this.on(type, g);

            return this;
        };
        EventEmitter.prototype.removeListener = function(type, listener) {
            var list, position, length, i;

            if (!isFunction(listener))
                throw TypeError('listener must be a function');

            if (!this._events || !this._events[type])
                return this;

            list = this._events[type];
            length = list.length;
            position = -1;

            if (list === listener ||
                (isFunction(list.listener) && list.listener === listener)) {
                delete this._events[type];
                if (this._events.removeListener)
                    this.emit('removeListener', type, listener);

            } else if (isObject(list)) {
                for (i = length; i-- > 0;) {
                    if (list[i] === listener ||
                        (list[i].listener && list[i].listener === listener)) {
                        position = i;
                        break;
                    }
                }

                if (position < 0)
                    return this;

                if (list.length === 1) {
                    list.length = 0;
                    delete this._events[type];
                } else {
                    list.splice(position, 1);
                }

                if (this._events.removeListener)
                    this.emit('removeListener', type, listener);
            }

            return this;
        };

        EventEmitter.prototype.removeAllListeners = function(type) {
            var key, listeners;

            if (!this._events)
                return this;
            if (!this._events.removeListener) {
                if (arguments.length === 0)
                    this._events = {};
                else if (this._events[type])
                    delete this._events[type];
                return this;
            }
            if (arguments.length === 0) {
                for (key in this._events) {
                    if (key === 'removeListener') continue;
                    this.removeAllListeners(key);
                }
                this.removeAllListeners('removeListener');
                this._events = {};
                return this;
            }

            listeners = this._events[type];

            if (isFunction(listeners)) {
                this.removeListener(type, listeners);
            } else {
                while (listeners.length)
                    this.removeListener(type, listeners[listeners.length - 1]);
            }
            delete this._events[type];

            return this;
        };

        EventEmitter.prototype.listeners = function(type) {
            var ret;
            if (!this._events || !this._events[type])
                ret = [];
            else if (isFunction(this._events[type]))
                ret = [this._events[type]];
            else
                ret = this._events[type].slice();
            return ret;
        };

        EventEmitter.listenerCount = function(emitter, type) {
            var ret;
            if (!emitter._events || !emitter._events[type])
                ret = 0;
            else if (isFunction(emitter._events[type]))
                ret = 1;
            else
                ret = emitter._events[type].length;
            return ret;
        };

        function isFunction(arg) {
            return typeof arg === 'function';
        }

        function isNumber(arg) {
            return typeof arg === 'number';
        }

        function isObject(arg) {
            return typeof arg === 'object' && arg !== null;
        }

        function isUndefined(arg) {
            return arg === void 0;
        }

    },{}],"/node_modules/jshint/data/ascii-identifier-data.js":[function(_dereq_,module,exports){
        var identifierStartTable = [];

        for (var i = 0; i < 128; i++) {
            identifierStartTable[i] =
                i === 36 ||           // $
                i >= 65 && i <= 90 || // A-Z
                i === 95 ||           // _
                i >= 97 && i <= 122;  // a-z
        }

        var identifierPartTable = [];

        for (var i = 0; i < 128; i++) {
            identifierPartTable[i] =
                identifierStartTable[i] || // $, _, A-Z, a-z
                i >= 48 && i <= 57;        // 0-9
        }

        module.exports = {
            asciiIdentifierStartTable: identifierStartTable,
            asciiIdentifierPartTable: identifierPartTable
        };

    },{}],"/node_modules/jshint/lodash.js":[function(_dereq_,module,exports){
        (function (global){
            ;(function() {

                var undefined;

                var VERSION = '3.7.0';

                var FUNC_ERROR_TEXT = 'Expected a function';

                var argsTag = '[object Arguments]',
                    arrayTag = '[object Array]',
                    boolTag = '[object Boolean]',
                    dateTag = '[object Date]',
                    errorTag = '[object Error]',
                    funcTag = '[object Function]',
                    mapTag = '[object Map]',
                    numberTag = '[object Number]',
                    objectTag = '[object Object]',
                    regexpTag = '[object RegExp]',
                    setTag = '[object Set]',
                    stringTag = '[object String]',
                    weakMapTag = '[object WeakMap]';

                var arrayBufferTag = '[object ArrayBuffer]',
                    float32Tag = '[object Float32Array]',
                    float64Tag = '[object Float64Array]',
                    int8Tag = '[object Int8Array]',
                    int16Tag = '[object Int16Array]',
                    int32Tag = '[object Int32Array]',
                    uint8Tag = '[object Uint8Array]',
                    uint8ClampedTag = '[object Uint8ClampedArray]',
                    uint16Tag = '[object Uint16Array]',
                    uint32Tag = '[object Uint32Array]';

                var reIsDeepProp = /\.|\[(?:[^[\]]+|(["'])(?:(?!\1)[^\n\\]|\\.)*?)\1\]/,
                    reIsPlainProp = /^\w*$/,
                    rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\n\\]|\\.)*?)\2)\]/g;

                var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g,
                    reHasRegExpChars = RegExp(reRegExpChars.source);

                var reEscapeChar = /\\(\\)?/g;

                var reFlags = /\w*$/;

                var reIsHostCtor = /^\[object .+?Constructor\]$/;

                var typedArrayTags = {};
                typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
                    typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
                        typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
                            typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
                                typedArrayTags[uint32Tag] = true;
                typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
                    typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
                        typedArrayTags[dateTag] = typedArrayTags[errorTag] =
                            typedArrayTags[funcTag] = typedArrayTags[mapTag] =
                                typedArrayTags[numberTag] = typedArrayTags[objectTag] =
                                    typedArrayTags[regexpTag] = typedArrayTags[setTag] =
                                        typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;

                var cloneableTags = {};
                cloneableTags[argsTag] = cloneableTags[arrayTag] =
                    cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
                        cloneableTags[dateTag] = cloneableTags[float32Tag] =
                            cloneableTags[float64Tag] = cloneableTags[int8Tag] =
                                cloneableTags[int16Tag] = cloneableTags[int32Tag] =
                                    cloneableTags[numberTag] = cloneableTags[objectTag] =
                                        cloneableTags[regexpTag] = cloneableTags[stringTag] =
                                            cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
                                                cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
                cloneableTags[errorTag] = cloneableTags[funcTag] =
                    cloneableTags[mapTag] = cloneableTags[setTag] =
                        cloneableTags[weakMapTag] = false;

                var objectTypes = {
                    'function': true,
                    'object': true
                };

                var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;

                var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;

                var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global;

                var freeSelf = objectTypes[typeof self] && self && self.Object && self;

                var freeWindow = objectTypes[typeof window] && window && window.Object && window;

                var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;

                var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this;

                function baseFindIndex(array, predicate, fromRight) {
                    var length = array.length,
                        index = fromRight ? length : -1;

                    while ((fromRight ? index-- : ++index < length)) {
                        if (predicate(array[index], index, array)) {
                            return index;
                        }
                    }
                    return -1;
                }

                function baseIndexOf(array, value, fromIndex) {
                    if (value !== value) {
                        return indexOfNaN(array, fromIndex);
                    }
                    var index = fromIndex - 1,
                        length = array.length;

                    while (++index < length) {
                        if (array[index] === value) {
                            return index;
                        }
                    }
                    return -1;
                }

                function baseIsFunction(value) {
                    return typeof value == 'function' || false;
                }

                function baseToString(value) {
                    if (typeof value == 'string') {
                        return value;
                    }
                    return value == null ? '' : (value + '');
                }

                function indexOfNaN(array, fromIndex, fromRight) {
                    var length = array.length,
                        index = fromIndex + (fromRight ? 0 : -1);

                    while ((fromRight ? index-- : ++index < length)) {
                        var other = array[index];
                        if (other !== other) {
                            return index;
                        }
                    }
                    return -1;
                }

                function isObjectLike(value) {
                    return !!value && typeof value == 'object';
                }

                var arrayProto = Array.prototype,
                    objectProto = Object.prototype;

                var fnToString = Function.prototype.toString;

                var hasOwnProperty = objectProto.hasOwnProperty;

                var objToString = objectProto.toString;

                var reIsNative = RegExp('^' +
                    escapeRegExp(objToString)
                        .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
                );

                var ArrayBuffer = isNative(ArrayBuffer = root.ArrayBuffer) && ArrayBuffer,
                    bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice,
                    floor = Math.floor,
                    getOwnPropertySymbols = isNative(getOwnPropertySymbols = Object.getOwnPropertySymbols) && getOwnPropertySymbols,
                    getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
                    push = arrayProto.push,
                    preventExtensions = isNative(Object.preventExtensions = Object.preventExtensions) && preventExtensions,
                    propertyIsEnumerable = objectProto.propertyIsEnumerable,
                    Uint8Array = isNative(Uint8Array = root.Uint8Array) && Uint8Array;

                var Float64Array = (function() {
                    try {
                        var func = isNative(func = root.Float64Array) && func,
                            result = new func(new ArrayBuffer(10), 0, 1) && func;
                    } catch(e) {}
                    return result;
                }());

                var nativeAssign = (function() {
                    var object = { '1': 0 },
                        func = preventExtensions && isNative(func = Object.assign) && func;

                    try { func(preventExtensions(object), 'xo'); } catch(e) {}
                    return !object[1] && func;
                }());

                var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray,
                    nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys,
                    nativeMax = Math.max,
                    nativeMin = Math.min;

                var NEGATIVE_INFINITY = Number.NEGATIVE_INFINITY;

                var MAX_ARRAY_LENGTH = Math.pow(2, 32) - 1,
                    MAX_ARRAY_INDEX =  MAX_ARRAY_LENGTH - 1,
                    HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;

                var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0;

                var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;

                function lodash() {
                }

                var support = lodash.support = {};

                (function(x) {
                    var Ctor = function() { this.x = x; },
                        object = { '0': x, 'length': x },
                        props = [];

                    Ctor.prototype = { 'valueOf': x, 'y': x };
                    for (var key in new Ctor) { props.push(key); }

                    support.funcDecomp = /\bthis\b/.test(function() { return this; });

                    support.funcNames = typeof Function.name == 'string';

                    try {
                        support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1);
                    } catch(e) {
                        support.nonEnumArgs = true;
                    }
                }(1, 0));

                function arrayCopy(source, array) {
                    var index = -1,
                        length = source.length;

                    array || (array = Array(length));
                    while (++index < length) {
                        array[index] = source[index];
                    }
                    return array;
                }

                function arrayEach(array, iteratee) {
                    var index = -1,
                        length = array.length;

                    while (++index < length) {
                        if (iteratee(array[index], index, array) === false) {
                            break;
                        }
                    }
                    return array;
                }

                function arrayFilter(array, predicate) {
                    var index = -1,
                        length = array.length,
                        resIndex = -1,
                        result = [];

                    while (++index < length) {
                        var value = array[index];
                        if (predicate(value, index, array)) {
                            result[++resIndex] = value;
                        }
                    }
                    return result;
                }

                function arrayMap(array, iteratee) {
                    var index = -1,
                        length = array.length,
                        result = Array(length);

                    while (++index < length) {
                        result[index] = iteratee(array[index], index, array);
                    }
                    return result;
                }

                function arrayMax(array) {
                    var index = -1,
                        length = array.length,
                        result = NEGATIVE_INFINITY;

                    while (++index < length) {
                        var value = array[index];
                        if (value > result) {
                            result = value;
                        }
                    }
                    return result;
                }

                function arraySome(array, predicate) {
                    var index = -1,
                        length = array.length;

                    while (++index < length) {
                        if (predicate(array[index], index, array)) {
                            return true;
                        }
                    }
                    return false;
                }

                function assignWith(object, source, customizer) {
                    var props = keys(source);
                    push.apply(props, getSymbols(source));

                    var index = -1,
                        length = props.length;

                    while (++index < length) {
                        var key = props[index],
                            value = object[key],
                            result = customizer(value, source[key], key, object, source);

                        if ((result === result ? (result !== value) : (value === value)) ||
                            (value === undefined && !(key in object))) {
                            object[key] = result;
                        }
                    }
                    return object;
                }

                var baseAssign = nativeAssign || function(object, source) {
                        return source == null
                            ? object
                            : baseCopy(source, getSymbols(source), baseCopy(source, keys(source), object));
                    };

                function baseCopy(source, props, object) {
                    object || (object = {});

                    var index = -1,
                        length = props.length;

                    while (++index < length) {
                        var key = props[index];
                        object[key] = source[key];
                    }
                    return object;
                }

                function baseCallback(func, thisArg, argCount) {
                    var type = typeof func;
                    if (type == 'function') {
                        return thisArg === undefined
                            ? func
                            : bindCallback(func, thisArg, argCount);
                    }
                    if (func == null) {
                        return identity;
                    }
                    if (type == 'object') {
                        return baseMatches(func);
                    }
                    return thisArg === undefined
                        ? property(func)
                        : baseMatchesProperty(func, thisArg);
                }

                function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
                    var result;
                    if (customizer) {
                        result = object ? customizer(value, key, object) : customizer(value);
                    }
                    if (result !== undefined) {
                        return result;
                    }
                    if (!isObject(value)) {
                        return value;
                    }
                    var isArr = isArray(value);
                    if (isArr) {
                        result = initCloneArray(value);
                        if (!isDeep) {
                            return arrayCopy(value, result);
                        }
                    } else {
                        var tag = objToString.call(value),
                            isFunc = tag == funcTag;

                        if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
                            result = initCloneObject(isFunc ? {} : value);
                            if (!isDeep) {
                                return baseAssign(result, value);
                            }
                        } else {
                            return cloneableTags[tag]
                                ? initCloneByTag(value, tag, isDeep)
                                : (object ? value : {});
                        }
                    }
                    stackA || (stackA = []);
                    stackB || (stackB = []);

                    var length = stackA.length;
                    while (length--) {
                        if (stackA[length] == value) {
                            return stackB[length];
                        }
                    }
                    stackA.push(value);
                    stackB.push(result);

                    (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
                        result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
                    });
                    return result;
                }

                var baseEach = createBaseEach(baseForOwn);

                function baseFilter(collection, predicate) {
                    var result = [];
                    baseEach(collection, function(value, index, collection) {
                        if (predicate(value, index, collection)) {
                            result.push(value);
                        }
                    });
                    return result;
                }

                var baseFor = createBaseFor();

                function baseForIn(object, iteratee) {
                    return baseFor(object, iteratee, keysIn);
                }

                function baseForOwn(object, iteratee) {
                    return baseFor(object, iteratee, keys);
                }

                function baseGet(object, path, pathKey) {
                    if (object == null) {
                        return;
                    }
                    if (pathKey !== undefined && pathKey in toObject(object)) {
                        path = [pathKey];
                    }
                    var index = -1,
                        length = path.length;

                    while (object != null && ++index < length) {
                        var result = object = object[path[index]];
                    }
                    return result;
                }

                function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) {
                    if (value === other) {
                        return value !== 0 || (1 / value == 1 / other);
                    }
                    var valType = typeof value,
                        othType = typeof other;

                    if ((valType != 'function' && valType != 'object' && othType != 'function' && othType != 'object') ||
                        value == null || other == null) {
                        return value !== value && other !== other;
                    }
                    return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB);
                }

                function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
                    var objIsArr = isArray(object),
                        othIsArr = isArray(other),
                        objTag = arrayTag,
                        othTag = arrayTag;

                    if (!objIsArr) {
                        objTag = objToString.call(object);
                        if (objTag == argsTag) {
                            objTag = objectTag;
                        } else if (objTag != objectTag) {
                            objIsArr = isTypedArray(object);
                        }
                    }
                    if (!othIsArr) {
                        othTag = objToString.call(other);
                        if (othTag == argsTag) {
                            othTag = objectTag;
                        } else if (othTag != objectTag) {
                            othIsArr = isTypedArray(other);
                        }
                    }
                    var objIsObj = objTag == objectTag,
                        othIsObj = othTag == objectTag,
                        isSameTag = objTag == othTag;

                    if (isSameTag && !(objIsArr || objIsObj)) {
                        return equalByTag(object, other, objTag);
                    }
                    if (!isLoose) {
                        var valWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
                            othWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');

                        if (valWrapped || othWrapped) {
                            return equalFunc(valWrapped ? object.value() : object, othWrapped ? other.value() : other, customizer, isLoose, stackA, stackB);
                        }
                    }
                    if (!isSameTag) {
                        return false;
                    }
                    stackA || (stackA = []);
                    stackB || (stackB = []);

                    var length = stackA.length;
                    while (length--) {
                        if (stackA[length] == object) {
                            return stackB[length] == other;
                        }
                    }
                    stackA.push(object);
                    stackB.push(other);

                    var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB);

                    stackA.pop();
                    stackB.pop();

                    return result;
                }

                function baseIsMatch(object, props, values, strictCompareFlags, customizer) {
                    var index = -1,
                        length = props.length,
                        noCustomizer = !customizer;

                    while (++index < length) {
                        if ((noCustomizer && strictCompareFlags[index])
                                ? values[index] !== object[props[index]]
                                : !(props[index] in object)
                        ) {
                            return false;
                        }
                    }
                    index = -1;
                    while (++index < length) {
                        var key = props[index],
                            objValue = object[key],
                            srcValue = values[index];

                        if (noCustomizer && strictCompareFlags[index]) {
                            var result = objValue !== undefined || (key in object);
                        } else {
                            result = customizer ? customizer(objValue, srcValue, key) : undefined;
                            if (result === undefined) {
                                result = baseIsEqual(srcValue, objValue, customizer, true);
                            }
                        }
                        if (!result) {
                            return false;
                        }
                    }
                    return true;
                }

                function baseMatches(source) {
                    var props = keys(source),
                        length = props.length;

                    if (!length) {
                        return constant(true);
                    }
                    if (length == 1) {
                        var key = props[0],
                            value = source[key];

                        if (isStrictComparable(value)) {
                            return function(object) {
                                if (object == null) {
                                    return false;
                                }
                                return object[key] === value && (value !== undefined || (key in toObject(object)));
                            };
                        }
                    }
                    var values = Array(length),
                        strictCompareFlags = Array(length);

                    while (length--) {
                        value = source[props[length]];
                        values[length] = value;
                        strictCompareFlags[length] = isStrictComparable(value);
                    }
                    return function(object) {
                        return object != null && baseIsMatch(toObject(object), props, values, strictCompareFlags);
                    };
                }

                function baseMatchesProperty(path, value) {
                    var isArr = isArray(path),
                        isCommon = isKey(path) && isStrictComparable(value),
                        pathKey = (path + '');

                    path = toPath(path);
                    return function(object) {
                        if (object == null) {
                            return false;
                        }
                        var key = pathKey;
                        object = toObject(object);
                        if ((isArr || !isCommon) && !(key in object)) {
                            object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
                            if (object == null) {
                                return false;
                            }
                            key = last(path);
                            object = toObject(object);
                        }
                        return object[key] === value
                            ? (value !== undefined || (key in object))
                            : baseIsEqual(value, object[key], null, true);
                    };
                }

                function baseMerge(object, source, customizer, stackA, stackB) {
                    if (!isObject(object)) {
                        return object;
                    }
                    var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source));
                    if (!isSrcArr) {
                        var props = keys(source);
                        push.apply(props, getSymbols(source));
                    }
                    arrayEach(props || source, function(srcValue, key) {
                        if (props) {
                            key = srcValue;
                            srcValue = source[key];
                        }
                        if (isObjectLike(srcValue)) {
                            stackA || (stackA = []);
                            stackB || (stackB = []);
                            baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
                        }
                        else {
                            var value = object[key],
                                result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
                                isCommon = result === undefined;

                            if (isCommon) {
                                result = srcValue;
                            }
                            if ((isSrcArr || result !== undefined) &&
                                (isCommon || (result === result ? (result !== value) : (value === value)))) {
                                object[key] = result;
                            }
                        }
                    });
                    return object;
                }

                function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
                    var length = stackA.length,
                        srcValue = source[key];

                    while (length--) {
                        if (stackA[length] == srcValue) {
                            object[key] = stackB[length];
                            return;
                        }
                    }
                    var value = object[key],
                        result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
                        isCommon = result === undefined;

                    if (isCommon) {
                        result = srcValue;
                        if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) {
                            result = isArray(value)
                                ? value
                                : (getLength(value) ? arrayCopy(value) : []);
                        }
                        else if (isPlainObject(srcValue) || isArguments(srcValue)) {
                            result = isArguments(value)
                                ? toPlainObject(value)
                                : (isPlainObject(value) ? value : {});
                        }
                        else {
                            isCommon = false;
                        }
                    }
                    stackA.push(srcValue);
                    stackB.push(result);

                    if (isCommon) {
                        object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
                    } else if (result === result ? (result !== value) : (value === value)) {
                        object[key] = result;
                    }
                }

                function baseProperty(key) {
                    return function(object) {
                        return object == null ? undefined : object[key];
                    };
                }

                function basePropertyDeep(path) {
                    var pathKey = (path + '');
                    path = toPath(path);
                    return function(object) {
                        return baseGet(object, path, pathKey);
                    };
                }

                function baseSlice(array, start, end) {
                    var index = -1,
                        length = array.length;

                    start = start == null ? 0 : (+start || 0);
                    if (start < 0) {
                        start = -start > length ? 0 : (length + start);
                    }
                    end = (end === undefined || end > length) ? length : (+end || 0);
                    if (end < 0) {
                        end += length;
                    }
                    length = start > end ? 0 : ((end - start) >>> 0);
                    start >>>= 0;

                    var result = Array(length);
                    while (++index < length) {
                        result[index] = array[index + start];
                    }
                    return result;
                }

                function baseSome(collection, predicate) {
                    var result;

                    baseEach(collection, function(value, index, collection) {
                        result = predicate(value, index, collection);
                        return !result;
                    });
                    return !!result;
                }

                function baseValues(object, props) {
                    var index = -1,
                        length = props.length,
                        result = Array(length);

                    while (++index < length) {
                        result[index] = object[props[index]];
                    }
                    return result;
                }

                function binaryIndex(array, value, retHighest) {
                    var low = 0,
                        high = array ? array.length : low;

                    if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
                        while (low < high) {
                            var mid = (low + high) >>> 1,
                                computed = array[mid];

                            if (retHighest ? (computed <= value) : (computed < value)) {
                                low = mid + 1;
                            } else {
                                high = mid;
                            }
                        }
                        return high;
                    }
                    return binaryIndexBy(array, value, identity, retHighest);
                }

                function binaryIndexBy(array, value, iteratee, retHighest) {
                    value = iteratee(value);

                    var low = 0,
                        high = array ? array.length : 0,
                        valIsNaN = value !== value,
                        valIsUndef = value === undefined;

                    while (low < high) {
                        var mid = floor((low + high) / 2),
                            computed = iteratee(array[mid]),
                            isReflexive = computed === computed;

                        if (valIsNaN) {
                            var setLow = isReflexive || retHighest;
                        } else if (valIsUndef) {
                            setLow = isReflexive && (retHighest || computed !== undefined);
                        } else {
                            setLow = retHighest ? (computed <= value) : (computed < value);
                        }
                        if (setLow) {
                            low = mid + 1;
                        } else {
                            high = mid;
                        }
                    }
                    return nativeMin(high, MAX_ARRAY_INDEX);
                }

                function bindCallback(func, thisArg, argCount) {
                    if (typeof func != 'function') {
                        return identity;
                    }
                    if (thisArg === undefined) {
                        return func;
                    }
                    switch (argCount) {
                        case 1: return function(value) {
                            return func.call(thisArg, value);
                        };
                        case 3: return function(value, index, collection) {
                            return func.call(thisArg, value, index, collection);
                        };
                        case 4: return function(accumulator, value, index, collection) {
                            return func.call(thisArg, accumulator, value, index, collection);
                        };
                        case 5: return function(value, other, key, object, source) {
                            return func.call(thisArg, value, other, key, object, source);
                        };
                    }
                    return function() {
                        return func.apply(thisArg, arguments);
                    };
                }

                function bufferClone(buffer) {
                    return bufferSlice.call(buffer, 0);
                }
                if (!bufferSlice) {
                    bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) {
                            var byteLength = buffer.byteLength,
                                floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0,
                                offset = floatLength * FLOAT64_BYTES_PER_ELEMENT,
                                result = new ArrayBuffer(byteLength);

                            if (floatLength) {
                                var view = new Float64Array(result, 0, floatLength);
                                view.set(new Float64Array(buffer, 0, floatLength));
                            }
                            if (byteLength != offset) {
                                view = new Uint8Array(result, offset);
                                view.set(new Uint8Array(buffer, offset));
                            }
                            return result;
                        };
                }

                function createAssigner(assigner) {
                    return restParam(function(object, sources) {
                        var index = -1,
                            length = object == null ? 0 : sources.length,
                            customizer = length > 2 && sources[length - 2],
                            guard = length > 2 && sources[2],
                            thisArg = length > 1 && sources[length - 1];

                        if (typeof customizer == 'function') {
                            customizer = bindCallback(customizer, thisArg, 5);
                            length -= 2;
                        } else {
                            customizer = typeof thisArg == 'function' ? thisArg : null;
                            length -= (customizer ? 1 : 0);
                        }
                        if (guard && isIterateeCall(sources[0], sources[1], guard)) {
                            customizer = length < 3 ? null : customizer;
                            length = 1;
                        }
                        while (++index < length) {
                            var source = sources[index];
                            if (source) {
                                assigner(object, source, customizer);
                            }
                        }
                        return object;
                    });
                }

                function createBaseEach(eachFunc, fromRight) {
                    return function(collection, iteratee) {
                        var length = collection ? getLength(collection) : 0;
                        if (!isLength(length)) {
                            return eachFunc(collection, iteratee);
                        }
                        var index = fromRight ? length : -1,
                            iterable = toObject(collection);

                        while ((fromRight ? index-- : ++index < length)) {
                            if (iteratee(iterable[index], index, iterable) === false) {
                                break;
                            }
                        }
                        return collection;
                    };
                }

                function createBaseFor(fromRight) {
                    return function(object, iteratee, keysFunc) {
                        var iterable = toObject(object),
                            props = keysFunc(object),
                            length = props.length,
                            index = fromRight ? length : -1;

                        while ((fromRight ? index-- : ++index < length)) {
                            var key = props[index];
                            if (iteratee(iterable[key], key, iterable) === false) {
                                break;
                            }
                        }
                        return object;
                    };
                }

                function createFindIndex(fromRight) {
                    return function(array, predicate, thisArg) {
                        if (!(array && array.length)) {
                            return -1;
                        }
                        predicate = getCallback(predicate, thisArg, 3);
                        return baseFindIndex(array, predicate, fromRight);
                    };
                }

                function createForEach(arrayFunc, eachFunc) {
                    return function(collection, iteratee, thisArg) {
                        return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection))
                            ? arrayFunc(collection, iteratee)
                            : eachFunc(collection, bindCallback(iteratee, thisArg, 3));
                    };
                }

                function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) {
                    var index = -1,
                        arrLength = array.length,
                        othLength = other.length,
                        result = true;

                    if (arrLength != othLength && !(isLoose && othLength > arrLength)) {
                        return false;
                    }
                    while (result && ++index < arrLength) {
                        var arrValue = array[index],
                            othValue = other[index];

                        result = undefined;
                        if (customizer) {
                            result = isLoose
                                ? customizer(othValue, arrValue, index)
                                : customizer(arrValue, othValue, index);
                        }
                        if (result === undefined) {
                            if (isLoose) {
                                var othIndex = othLength;
                                while (othIndex--) {
                                    othValue = other[othIndex];
                                    result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB);
                                    if (result) {
                                        break;
                                    }
                                }
                            } else {
                                result = (arrValue && arrValue === othValue) || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB);
                            }
                        }
                    }
                    return !!result;
                }

                function equalByTag(object, other, tag) {
                    switch (tag) {
                        case boolTag:
                        case dateTag:
                            return +object == +other;

                        case errorTag:
                            return object.name == other.name && object.message == other.message;

                        case numberTag:
                            return (object != +object)
                                ? other != +other
                                : (object == 0 ? ((1 / object) == (1 / other)) : object == +other);

                        case regexpTag:
                        case stringTag:
                            return object == (other + '');
                    }
                    return false;
                }

                function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
                    var objProps = keys(object),
                        objLength = objProps.length,
                        othProps = keys(other),
                        othLength = othProps.length;

                    if (objLength != othLength && !isLoose) {
                        return false;
                    }
                    var skipCtor = isLoose,
                        index = -1;

                    while (++index < objLength) {
                        var key = objProps[index],
                            result = isLoose ? key in other : hasOwnProperty.call(other, key);

                        if (result) {
                            var objValue = object[key],
                                othValue = other[key];

                            result = undefined;
                            if (customizer) {
                                result = isLoose
                                    ? customizer(othValue, objValue, key)
                                    : customizer(objValue, othValue, key);
                            }
                            if (result === undefined) {
                                result = (objValue && objValue === othValue) || equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB);
                            }
                        }
                        if (!result) {
                            return false;
                        }
                        skipCtor || (skipCtor = key == 'constructor');
                    }
                    if (!skipCtor) {
                        var objCtor = object.constructor,
                            othCtor = other.constructor;

                        if (objCtor != othCtor &&
                            ('constructor' in object && 'constructor' in other) &&
                            !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
                            typeof othCtor == 'function' && othCtor instanceof othCtor)) {
                            return false;
                        }
                    }
                    return true;
                }

                function getCallback(func, thisArg, argCount) {
                    var result = lodash.callback || callback;
                    result = result === callback ? baseCallback : result;
                    return argCount ? result(func, thisArg, argCount) : result;
                }

                function getIndexOf(collection, target, fromIndex) {
                    var result = lodash.indexOf || indexOf;
                    result = result === indexOf ? baseIndexOf : result;
                    return collection ? result(collection, target, fromIndex) : result;
                }

                var getLength = baseProperty('length');

                var getSymbols = !getOwnPropertySymbols ? constant([]) : function(object) {
                        return getOwnPropertySymbols(toObject(object));
                    };

                function initCloneArray(array) {
                    var length = array.length,
                        result = new array.constructor(length);

                    if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
                        result.index = array.index;
                        result.input = array.input;
                    }
                    return result;
                }

                function initCloneObject(object) {
                    var Ctor = object.constructor;
                    if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
                        Ctor = Object;
                    }
                    return new Ctor;
                }

                function initCloneByTag(object, tag, isDeep) {
                    var Ctor = object.constructor;
                    switch (tag) {
                        case arrayBufferTag:
                            return bufferClone(object);

                        case boolTag:
                        case dateTag:
                            return new Ctor(+object);

                        case float32Tag: case float64Tag:
                        case int8Tag: case int16Tag: case int32Tag:
                        case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
                        var buffer = object.buffer;
                        return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);

                        case numberTag:
                        case stringTag:
                            return new Ctor(object);

                        case regexpTag:
                            var result = new Ctor(object.source, reFlags.exec(object));
                            result.lastIndex = object.lastIndex;
                    }
                    return result;
                }

                function isIndex(value, length) {
                    value = +value;
                    length = length == null ? MAX_SAFE_INTEGER : length;
                    return value > -1 && value % 1 == 0 && value < length;
                }

                function isIterateeCall(value, index, object) {
                    if (!isObject(object)) {
                        return false;
                    }
                    var type = typeof index;
                    if (type == 'number') {
                        var length = getLength(object),
                            prereq = isLength(length) && isIndex(index, length);
                    } else {
                        prereq = type == 'string' && index in object;
                    }
                    if (prereq) {
                        var other = object[index];
                        return value === value ? (value === other) : (other !== other);
                    }
                    return false;
                }

                function isKey(value, object) {
                    var type = typeof value;
                    if ((type == 'string' && reIsPlainProp.test(value)) || type == 'number') {
                        return true;
                    }
                    if (isArray(value)) {
                        return false;
                    }
                    var result = !reIsDeepProp.test(value);
                    return result || (object != null && value in toObject(object));
                }

                function isLength(value) {
                    return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
                }

                function isStrictComparable(value) {
                    return value === value && (value === 0 ? ((1 / value) > 0) : !isObject(value));
                }

                function shimIsPlainObject(value) {
                    var Ctor,
                        support = lodash.support;

                    if (!(isObjectLike(value) && objToString.call(value) == objectTag) ||
                        (!hasOwnProperty.call(value, 'constructor') &&
                        (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
                        return false;
                    }
                    var result;
                    baseForIn(value, function(subValue, key) {
                        result = key;
                    });
                    return result === undefined || hasOwnProperty.call(value, result);
                }

                function shimKeys(object) {
                    var props = keysIn(object),
                        propsLength = props.length,
                        length = propsLength && object.length,
                        support = lodash.support;

                    var allowIndexes = length && isLength(length) &&
                        (isArray(object) || (support.nonEnumArgs && isArguments(object)));

                    var index = -1,
                        result = [];

                    while (++index < propsLength) {
                        var key = props[index];
                        if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
                            result.push(key);
                        }
                    }
                    return result;
                }

                function toObject(value) {
                    return isObject(value) ? value : Object(value);
                }

                function toPath(value) {
                    if (isArray(value)) {
                        return value;
                    }
                    var result = [];
                    baseToString(value).replace(rePropName, function(match, number, quote, string) {
                        result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
                    });
                    return result;
                }

                var findLastIndex = createFindIndex(true);

                function indexOf(array, value, fromIndex) {
                    var length = array ? array.length : 0;
                    if (!length) {
                        return -1;
                    }
                    if (typeof fromIndex == 'number') {
                        fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : fromIndex;
                    } else if (fromIndex) {
                        var index = binaryIndex(array, value),
                            other = array[index];

                        if (value === value ? (value === other) : (other !== other)) {
                            return index;
                        }
                        return -1;
                    }
                    return baseIndexOf(array, value, fromIndex || 0);
                }

                function last(array) {
                    var length = array ? array.length : 0;
                    return length ? array[length - 1] : undefined;
                }

                function slice(array, start, end) {
                    var length = array ? array.length : 0;
                    if (!length) {
                        return [];
                    }
                    if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
                        start = 0;
                        end = length;
                    }
                    return baseSlice(array, start, end);
                }

                function unzip(array) {
                    var index = -1,
                        length = (array && array.length && arrayMax(arrayMap(array, getLength))) >>> 0,
                        result = Array(length);

                    while (++index < length) {
                        result[index] = arrayMap(array, baseProperty(index));
                    }
                    return result;
                }

                var zip = restParam(unzip);

                var forEach = createForEach(arrayEach, baseEach);

                function includes(collection, target, fromIndex, guard) {
                    var length = collection ? getLength(collection) : 0;
                    if (!isLength(length)) {
                        collection = values(collection);
                        length = collection.length;
                    }
                    if (!length) {
                        return false;
                    }
                    if (typeof fromIndex != 'number' || (guard && isIterateeCall(target, fromIndex, guard))) {
                        fromIndex = 0;
                    } else {
                        fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
                    }
                    return (typeof collection == 'string' || !isArray(collection) && isString(collection))
                        ? (fromIndex < length && collection.indexOf(target, fromIndex) > -1)
                        : (getIndexOf(collection, target, fromIndex) > -1);
                }

                function reject(collection, predicate, thisArg) {
                    var func = isArray(collection) ? arrayFilter : baseFilter;
                    predicate = getCallback(predicate, thisArg, 3);
                    return func(collection, function(value, index, collection) {
                        return !predicate(value, index, collection);
                    });
                }

                function some(collection, predicate, thisArg) {
                    var func = isArray(collection) ? arraySome : baseSome;
                    if (thisArg && isIterateeCall(collection, predicate, thisArg)) {
                        predicate = null;
                    }
                    if (typeof predicate != 'function' || thisArg !== undefined) {
                        predicate = getCallback(predicate, thisArg, 3);
                    }
                    return func(collection, predicate);
                }

                function restParam(func, start) {
                    if (typeof func != 'function') {
                        throw new TypeError(FUNC_ERROR_TEXT);
                    }
                    start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);
                    return function() {
                        var args = arguments,
                            index = -1,
                            length = nativeMax(args.length - start, 0),
                            rest = Array(length);

                        while (++index < length) {
                            rest[index] = args[start + index];
                        }
                        switch (start) {
                            case 0: return func.call(this, rest);
                            case 1: return func.call(this, args[0], rest);
                            case 2: return func.call(this, args[0], args[1], rest);
                        }
                        var otherArgs = Array(start + 1);
                        index = -1;
                        while (++index < start) {
                            otherArgs[index] = args[index];
                        }
                        otherArgs[start] = rest;
                        return func.apply(this, otherArgs);
                    };
                }

                function clone(value, isDeep, customizer, thisArg) {
                    if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) {
                        isDeep = false;
                    }
                    else if (typeof isDeep == 'function') {
                        thisArg = customizer;
                        customizer = isDeep;
                        isDeep = false;
                    }
                    customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
                    return baseClone(value, isDeep, customizer);
                }

                function isArguments(value) {
                    var length = isObjectLike(value) ? value.length : undefined;
                    return isLength(length) && objToString.call(value) == argsTag;
                }

                var isArray = nativeIsArray || function(value) {
                        return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
                    };

                function isEmpty(value) {
                    if (value == null) {
                        return true;
                    }
                    var length = getLength(value);
                    if (isLength(length) && (isArray(value) || isString(value) || isArguments(value) ||
                        (isObjectLike(value) && isFunction(value.splice)))) {
                        return !length;
                    }
                    return !keys(value).length;
                }

                var isFunction = !(baseIsFunction(/x/) || (Uint8Array && !baseIsFunction(Uint8Array))) ? baseIsFunction : function(value) {
                        return objToString.call(value) == funcTag;
                    };

                function isObject(value) {
                    var type = typeof value;
                    return type == 'function' || (!!value && type == 'object');
                }

                function isNative(value) {
                    if (value == null) {
                        return false;
                    }
                    if (objToString.call(value) == funcTag) {
                        return reIsNative.test(fnToString.call(value));
                    }
                    return isObjectLike(value) && reIsHostCtor.test(value);
                }

                function isNumber(value) {
                    return typeof value == 'number' || (isObjectLike(value) && objToString.call(value) == numberTag);
                }

                var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) {
                        if (!(value && objToString.call(value) == objectTag)) {
                            return false;
                        }
                        var valueOf = value.valueOf,
                            objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);

                        return objProto
                            ? (value == objProto || getPrototypeOf(value) == objProto)
                            : shimIsPlainObject(value);
                    };

                function isString(value) {
                    return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag);
                }

                function isTypedArray(value) {
                    return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)];
                }

                function toPlainObject(value) {
                    return baseCopy(value, keysIn(value));
                }

                var assign = createAssigner(function(object, source, customizer) {
                    return customizer
                        ? assignWith(object, source, customizer)
                        : baseAssign(object, source);
                });

                function has(object, path) {
                    if (object == null) {
                        return false;
                    }
                    var result = hasOwnProperty.call(object, path);
                    if (!result && !isKey(path)) {
                        path = toPath(path);
                        object = path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
                        path = last(path);
                        result = object != null && hasOwnProperty.call(object, path);
                    }
                    return result;
                }

                var keys = !nativeKeys ? shimKeys : function(object) {
                        if (object) {
                            var Ctor = object.constructor,
                                length = object.length;
                        }
                        if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
                            (typeof object != 'function' && isLength(length))) {
                            return shimKeys(object);
                        }
                        return isObject(object) ? nativeKeys(object) : [];
                    };

                function keysIn(object) {
                    if (object == null) {
                        return [];
                    }
                    if (!isObject(object)) {
                        object = Object(object);
                    }
                    var length = object.length;
                    length = (length && isLength(length) &&
                        (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0;

                    var Ctor = object.constructor,
                        index = -1,
                        isProto = typeof Ctor == 'function' && Ctor.prototype === object,
                        result = Array(length),
                        skipIndexes = length > 0;

                    while (++index < length) {
                        result[index] = (index + '');
                    }
                    for (var key in object) {
                        if (!(skipIndexes && isIndex(key, length)) &&
                            !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
                            result.push(key);
                        }
                    }
                    return result;
                }

                var merge = createAssigner(baseMerge);

                function values(object) {
                    return baseValues(object, keys(object));
                }

                function escapeRegExp(string) {
                    string = baseToString(string);
                    return (string && reHasRegExpChars.test(string))
                        ? string.replace(reRegExpChars, '\\$&')
                        : string;
                }

                function callback(func, thisArg, guard) {
                    if (guard && isIterateeCall(func, thisArg, guard)) {
                        thisArg = null;
                    }
                    return baseCallback(func, thisArg);
                }

                function constant(value) {
                    return function() {
                        return value;
                    };
                }

                function identity(value) {
                    return value;
                }

                function property(path) {
                    return isKey(path) ? baseProperty(path) : basePropertyDeep(path);
                }
                lodash.assign = assign;
                lodash.callback = callback;
                lodash.constant = constant;
                lodash.forEach = forEach;
                lodash.keys = keys;
                lodash.keysIn = keysIn;
                lodash.merge = merge;
                lodash.property = property;
                lodash.reject = reject;
                lodash.restParam = restParam;
                lodash.slice = slice;
                lodash.toPlainObject = toPlainObject;
                lodash.unzip = unzip;
                lodash.values = values;
                lodash.zip = zip;

                lodash.each = forEach;
                lodash.extend = assign;
                lodash.iteratee = callback;
                lodash.clone = clone;
                lodash.escapeRegExp = escapeRegExp;
                lodash.findLastIndex = findLastIndex;
                lodash.has = has;
                lodash.identity = identity;
                lodash.includes = includes;
                lodash.indexOf = indexOf;
                lodash.isArguments = isArguments;
                lodash.isArray = isArray;
                lodash.isEmpty = isEmpty;
                lodash.isFunction = isFunction;
                lodash.isNative = isNative;
                lodash.isNumber = isNumber;
                lodash.isObject = isObject;
                lodash.isPlainObject = isPlainObject;
                lodash.isString = isString;
                lodash.isTypedArray = isTypedArray;
                lodash.last = last;
                lodash.some = some;

                lodash.any = some;
                lodash.contains = includes;
                lodash.include = includes;

                lodash.VERSION = VERSION;
                if (freeExports && freeModule) {
                    if (moduleExports) {
                        (freeModule.exports = lodash)._ = lodash;
                    }
                    else {
                        freeExports._ = lodash;
                    }
                }
                else {
                    root._ = lodash;
                }
            }.call(this));

        }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
    },{}],"/node_modules/jshint/src/jshint.js":[function(_dereq_,module,exports){

        var _            = _dereq_("../lodash");
        var events       = _dereq_("events");
        var vars         = _dereq_("./vars.js");
        var messages     = _dereq_("./messages.js");
        var Lexer        = _dereq_("./lex.js").Lexer;
        var reg          = _dereq_("./reg.js");
        var state        = _dereq_("./state.js").state;
        var style        = _dereq_("./style.js");
        var options      = _dereq_("./options.js");
        var scopeManager = _dereq_("./scope-manager.js");

        var JSHINT = (function() {
            "use strict";

            var api, // Extension API
                bang = {
                    "<"  : true,
                    "<=" : true,
                    "==" : true,
                    "===": true,
                    "!==": true,
                    "!=" : true,
                    ">"  : true,
                    ">=" : true,
                    "+"  : true,
                    "-"  : true,
                    "*"  : true,
                    "/"  : true,
                    "%"  : true
                },

                declared, // Globals that were declared using /*global ... */ syntax.

                functionicity = [
                    "closure", "exception", "global", "label",
                    "outer", "unused", "var"
                ],

                functions, // All of the functions

                inblock,
                indent,
                lookahead,
                lex,
                member,
                membersOnly,
                predefined,    // Global variables defined by option

                stack,
                urls,

                extraModules = [],
                emitter = new events.EventEmitter();

            function checkOption(name, t) {
                name = name.trim();

                if (/^[+-]W\d{3}$/g.test(name)) {
                    return true;
                }

                if (options.validNames.indexOf(name) === -1) {
                    if (t.type !== "jslint" && !_.has(options.removed, name)) {
                        error("E001", t, name);
                        return false;
                    }
                }

                return true;
            }

            function isString(obj) {
                return Object.prototype.toString.call(obj) === "[object String]";
            }

            function isIdentifier(tkn, value) {
                if (!tkn)
                    return false;

                if (!tkn.identifier || tkn.value !== value)
                    return false;

                return true;
            }

            function isReserved(token) {
                if (!token.reserved) {
                    return false;
                }
                var meta = token.meta;

                if (meta && meta.isFutureReservedWord && state.inES5()) {
                    if (!meta.es5) {
                        return false;
                    }
                    if (meta.strictOnly) {
                        if (!state.option.strict && !state.isStrict()) {
                            return false;
                        }
                    }

                    if (token.isProperty) {
                        return false;
                    }
                }

                return true;
            }

            function supplant(str, data) {
                return str.replace(/\{([^{}]*)\}/g, function(a, b) {
                    var r = data[b];
                    return typeof r === "string" || typeof r === "number" ? r : a;
                });
            }

            function combine(dest, src) {
                Object.keys(src).forEach(function(name) {
                    if (_.has(JSHINT.blacklist, name)) return;
                    dest[name] = src[name];
                });
            }

            function processenforceall() {
                if (state.option.enforceall) {
                    for (var enforceopt in options.bool.enforcing) {
                        if (state.option[enforceopt] === undefined &&
                            !options.noenforceall[enforceopt]) {
                            state.option[enforceopt] = true;
                        }
                    }
                    for (var relaxopt in options.bool.relaxing) {
                        if (state.option[relaxopt] === undefined) {
                            state.option[relaxopt] = false;
                        }
                    }
                }
            }

            function assume() {
                processenforceall();
                if (!state.option.esversion && !state.option.moz) {
                    if (state.option.es3) {
                        state.option.esversion = 3;
                    } else if (state.option.esnext) {
                        state.option.esversion = 6;
                    } else {
                        state.option.esversion = 5;
                    }
                }

                if (state.inES5()) {
                    combine(predefined, vars.ecmaIdentifiers[5]);
                }

                if (state.inES6()) {
                    combine(predefined, vars.ecmaIdentifiers[6]);
                }

                if (state.option.module) {
                    if (state.option.strict === true) {
                        state.option.strict = "global";
                    }
                    if (!state.inES6()) {
                        warning("W134", state.tokens.next, "module", 6);
                    }
                }

                if (state.option.couch) {
                    combine(predefined, vars.couch);
                }

                if (state.option.qunit) {
                    combine(predefined, vars.qunit);
                }

                if (state.option.rhino) {
                    combine(predefined, vars.rhino);
                }

                if (state.option.shelljs) {
                    combine(predefined, vars.shelljs);
                    combine(predefined, vars.node);
                }
                if (state.option.typed) {
                    combine(predefined, vars.typed);
                }

                if (state.option.phantom) {
                    combine(predefined, vars.phantom);
                    if (state.option.strict === true) {
                        state.option.strict = "global";
                    }
                }

                if (state.option.prototypejs) {
                    combine(predefined, vars.prototypejs);
                }

                if (state.option.node) {
                    combine(predefined, vars.node);
                    combine(predefined, vars.typed);
                    if (state.option.strict === true) {
                        state.option.strict = "global";
                    }
                }

                if (state.option.devel) {
                    combine(predefined, vars.devel);
                }

                if (state.option.dojo) {
                    combine(predefined, vars.dojo);
                }

                if (state.option.browser) {
                    combine(predefined, vars.browser);
                    combine(predefined, vars.typed);
                }

                if (state.option.browserify) {
                    combine(predefined, vars.browser);
                    combine(predefined, vars.typed);
                    combine(predefined, vars.browserify);
                    if (state.option.strict === true) {
                        state.option.strict = "global";
                    }
                }

                if (state.option.nonstandard) {
                    combine(predefined, vars.nonstandard);
                }

                if (state.option.jasmine) {
                    combine(predefined, vars.jasmine);
                }

                if (state.option.jquery) {
                    combine(predefined, vars.jquery);
                }

                if (state.option.mootools) {
                    combine(predefined, vars.mootools);
                }

                if (state.option.worker) {
                    combine(predefined, vars.worker);
                }

                if (state.option.wsh) {
                    combine(predefined, vars.wsh);
                }

                if (state.option.globalstrict && state.option.strict !== false) {
                    state.option.strict = "global";
                }

                if (state.option.yui) {
                    combine(predefined, vars.yui);
                }

                if (state.option.mocha) {
                    combine(predefined, vars.mocha);
                }
            }
            function quit(code, line, chr) {
                var percentage = Math.floor((line / state.lines.length) * 100);
                var message = messages.errors[code].desc;

                throw {
                    name: "JSHintError",
                    line: line,
                    character: chr,
                    message: message + " (" + percentage + "% scanned).",
                    raw: message,
                    code: code
                };
            }

            function removeIgnoredMessages() {
                var ignored = state.ignoredLines;

                if (_.isEmpty(ignored)) return;
                JSHINT.errors = _.reject(JSHINT.errors, function(err) { return ignored[err.line] });
            }

            function warning(code, t, a, b, c, d) {
                var ch, l, w, msg;

                if (/^W\d{3}$/.test(code)) {
                    if (state.ignored[code])
                        return;

                    msg = messages.warnings[code];
                } else if (/E\d{3}/.test(code)) {
                    msg = messages.errors[code];
                } else if (/I\d{3}/.test(code)) {
                    msg = messages.info[code];
                }

                t = t || state.tokens.next || {};
                if (t.id === "(end)") {  // `~
                    t = state.tokens.curr;
                }

                l = t.line || 0;
                ch = t.from || 0;

                w = {
                    id: "(error)",
                    raw: msg.desc,
                    code: msg.code,
                    evidence: state.lines[l - 1] || "",
                    line: l,
                    character: ch,
                    scope: JSHINT.scope,
                    a: a,
                    b: b,
                    c: c,
                    d: d
                };

                w.reason = supplant(msg.desc, w);
                JSHINT.errors.push(w);

                removeIgnoredMessages();

                if (JSHINT.errors.length >= state.option.maxerr)
                    quit("E043", l, ch);

                return w;
            }

            function warningAt(m, l, ch, a, b, c, d) {
                return warning(m, {
                    line: l,
                    from: ch
                }, a, b, c, d);
            }

            function error(m, t, a, b, c, d) {
                warning(m, t, a, b, c, d);
            }

            function errorAt(m, l, ch, a, b, c, d) {
                return error(m, {
                    line: l,
                    from: ch
                }, a, b, c, d);
            }
            function addInternalSrc(elem, src) {
                var i;
                i = {
                    id: "(internal)",
                    elem: elem,
                    value: src
                };
                JSHINT.internals.push(i);
                return i;
            }

            function doOption() {
                var nt = state.tokens.next;
                var body = nt.body.match(/(-\s+)?[^\s,:]+(?:\s*:\s*(-\s+)?[^\s,]+)?/g) || [];

                var predef = {};
                if (nt.type === "globals") {
                    body.forEach(function(g, idx) {
                        g = g.split(":");
                        var key = (g[0] || "").trim();
                        var val = (g[1] || "").trim();

                        if (key === "-" || !key.length) {
                            if (idx > 0 && idx === body.length - 1) {
                                return;
                            }
                            error("E002", nt);
                            return;
                        }

                        if (key.charAt(0) === "-") {
                            key = key.slice(1);
                            val = false;

                            JSHINT.blacklist[key] = key;
                            delete predefined[key];
                        } else {
                            predef[key] = (val === "true");
                        }
                    });

                    combine(predefined, predef);

                    for (var key in predef) {
                        if (_.has(predef, key)) {
                            declared[key] = nt;
                        }
                    }
                }

                if (nt.type === "exported") {
                    body.forEach(function(e, idx) {
                        if (!e.length) {
                            if (idx > 0 && idx === body.length - 1) {
                                return;
                            }
                            error("E002", nt);
                            return;
                        }

                        state.funct["(scope)"].addExported(e);
                    });
                }

                if (nt.type === "members") {
                    membersOnly = membersOnly || {};

                    body.forEach(function(m) {
                        var ch1 = m.charAt(0);
                        var ch2 = m.charAt(m.length - 1);

                        if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) {
                            m = m
                                .substr(1, m.length - 2)
                                .replace("\\\"", "\"");
                        }

                        membersOnly[m] = false;
                    });
                }

                var numvals = [
                    "maxstatements",
                    "maxparams",
                    "maxdepth",
                    "maxcomplexity",
                    "maxerr",
                    "maxlen",
                    "indent"
                ];

                if (nt.type === "jshint" || nt.type === "jslint") {
                    body.forEach(function(g) {
                        g = g.split(":");
                        var key = (g[0] || "").trim();
                        var val = (g[1] || "").trim();

                        if (!checkOption(key, nt)) {
                            return;
                        }

                        if (numvals.indexOf(key) >= 0) {
                            if (val !== "false") {
                                val = +val;

                                if (typeof val !== "number" || !isFinite(val) || val <= 0 || Math.floor(val) !== val) {
                                    error("E032", nt, g[1].trim());
                                    return;
                                }

                                state.option[key] = val;
                            } else {
                                state.option[key] = key === "indent" ? 4 : false;
                            }

                            return;
                        }

                        if (key === "validthis") {

                            if (state.funct["(global)"])
                                return void error("E009");

                            if (val !== "true" && val !== "false")
                                return void error("E002", nt);

                            state.option.validthis = (val === "true");
                            return;
                        }

                        if (key === "quotmark") {
                            switch (val) {
                                case "true":
                                case "false":
                                    state.option.quotmark = (val === "true");
                                    break;
                                case "double":
                                case "single":
                                    state.option.quotmark = val;
                                    break;
                                default:
                                    error("E002", nt);
                            }
                            return;
                        }

                        if (key === "shadow") {
                            switch (val) {
                                case "true":
                                    state.option.shadow = true;
                                    break;
                                case "outer":
                                    state.option.shadow = "outer";
                                    break;
                                case "false":
                                case "inner":
                                    state.option.shadow = "inner";
                                    break;
                                default:
                                    error("E002", nt);
                            }
                            return;
                        }

                        if (key === "unused") {
                            switch (val) {
                                case "true":
                                    state.option.unused = true;
                                    break;
                                case "false":
                                    state.option.unused = false;
                                    break;
                                case "vars":
                                case "strict":
                                    state.option.unused = val;
                                    break;
                                default:
                                    error("E002", nt);
                            }
                            return;
                        }

                        if (key === "latedef") {
                            switch (val) {
                                case "true":
                                    state.option.latedef = true;
                                    break;
                                case "false":
                                    state.option.latedef = false;
                                    break;
                                case "nofunc":
                                    state.option.latedef = "nofunc";
                                    break;
                                default:
                                    error("E002", nt);
                            }
                            return;
                        }

                        if (key === "ignore") {
                            switch (val) {
                                case "line":
                                    state.ignoredLines[nt.line] = true;
                                    removeIgnoredMessages();
                                    break;
                                default:
                                    error("E002", nt);
                            }
                            return;
                        }

                        if (key === "strict") {
                            switch (val) {
                                case "true":
                                    state.option.strict = true;
                                    break;
                                case "false":
                                    state.option.strict = false;
                                    break;
                                case "func":
                                case "global":
                                case "implied":
                                    state.option.strict = val;
                                    break;
                                default:
                                    error("E002", nt);
                            }
                            return;
                        }

                        if (key === "module") {
                            if (!hasParsedCode(state.funct)) {
                                error("E055", state.tokens.next, "module");
                            }
                        }
                        var esversions = {
                            es3   : 3,
                            es5   : 5,
                            esnext: 6
                        };
                        if (_.has(esversions, key)) {
                            switch (val) {
                                case "true":
                                    state.option.moz = false;
                                    state.option.esversion = esversions[key];
                                    break;
                                case "false":
                                    if (!state.option.moz) {
                                        state.option.esversion = 5;
                                    }
                                    break;
                                default:
                                    error("E002", nt);
                            }
                            return;
                        }

                        if (key === "esversion") {
                            switch (val) {
                                case "5":
                                    if (state.inES5(true)) {
                                        warning("I003");
                                    }
                                case "3":
                                case "6":
                                    state.option.moz = false;
                                    state.option.esversion = +val;
                                    break;
                                case "2015":
                                    state.option.moz = false;
                                    state.option.esversion = 6;
                                    break;
                                default:
                                    error("E002", nt);
                            }
                            if (!hasParsedCode(state.funct)) {
                                error("E055", state.tokens.next, "esversion");
                            }
                            return;
                        }

                        var match = /^([+-])(W\d{3})$/g.exec(key);
                        if (match) {
                            state.ignored[match[2]] = (match[1] === "-");
                            return;
                        }

                        var tn;
                        if (val === "true" || val === "false") {
                            if (nt.type === "jslint") {
                                tn = options.renamed[key] || key;
                                state.option[tn] = (val === "true");

                                if (options.inverted[tn] !== undefined) {
                                    state.option[tn] = !state.option[tn];
                                }
                            } else {
                                state.option[key] = (val === "true");
                            }

                            if (key === "newcap") {
                                state.option["(explicitNewcap)"] = true;
                            }
                            return;
                        }

                        error("E002", nt);
                    });

                    assume();
                }
            }

            function peek(p) {
                var i = p || 0, j = lookahead.length, t;

                if (i < j) {
                    return lookahead[i];
                }

                while (j <= i) {
                    t = lookahead[j];
                    if (!t) {
                        t = lookahead[j] = lex.token();
                    }
                    j += 1;
                }
                if (!t && state.tokens.next.id === "(end)") {
                    return state.tokens.next;
                }

                return t;
            }

            function peekIgnoreEOL() {
                var i = 0;
                var t;
                do {
                    t = peek(i++);
                } while (t.id === "(endline)");
                return t;
            }

            function advance(id, t) {

                switch (state.tokens.curr.id) {
                    case "(number)":
                        if (state.tokens.next.id === ".") {
                            warning("W005", state.tokens.curr);
                        }
                        break;
                    case "-":
                        if (state.tokens.next.id === "-" || state.tokens.next.id === "--") {
                            warning("W006");
                        }
                        break;
                    case "+":
                        if (state.tokens.next.id === "+" || state.tokens.next.id === "++") {
                            warning("W007");
                        }
                        break;
                }

                if (id && state.tokens.next.id !== id) {
                    if (t) {
                        if (state.tokens.next.id === "(end)") {
                            error("E019", t, t.id);
                        } else {
                            error("E020", state.tokens.next, id, t.id, t.line, state.tokens.next.value);
                        }
                    } else if (state.tokens.next.type !== "(identifier)" || state.tokens.next.value !== id) {
                        warning("W116", state.tokens.next, id, state.tokens.next.value);
                    }
                }

                state.tokens.prev = state.tokens.curr;
                state.tokens.curr = state.tokens.next;
                for (;;) {
                    state.tokens.next = lookahead.shift() || lex.token();

                    if (!state.tokens.next) { // No more tokens left, give up
                        quit("E041", state.tokens.curr.line);
                    }

                    if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") {
                        return;
                    }

                    if (state.tokens.next.check) {
                        state.tokens.next.check();
                    }

                    if (state.tokens.next.isSpecial) {
                        if (state.tokens.next.type === "falls through") {
                            state.tokens.curr.caseFallsThrough = true;
                        } else {
                            doOption();
                        }
                    } else {
                        if (state.tokens.next.id !== "(endline)") {
                            break;
                        }
                    }
                }
            }

            function isInfix(token) {
                return token.infix || (!token.identifier && !token.template && !!token.led);
            }

            function isEndOfExpr() {
                var curr = state.tokens.curr;
                var next = state.tokens.next;
                if (next.id === ";" || next.id === "}" || next.id === ":") {
                    return true;
                }
                if (isInfix(next) === isInfix(curr) || (curr.id === "yield" && state.inMoz())) {
                    return curr.line !== startLine(next);
                }
                return false;
            }

            function isBeginOfExpr(prev) {
                return !prev.left && prev.arity !== "unary";
            }

            function expression(rbp, initial) {
                var left, isArray = false, isObject = false, isLetExpr = false;

                state.nameStack.push();
                if (!initial && state.tokens.next.value === "let" && peek(0).value === "(") {
                    if (!state.inMoz()) {
                        warning("W118", state.tokens.next, "let expressions");
                    }
                    isLetExpr = true;
                    state.funct["(scope)"].stack();
                    advance("let");
                    advance("(");
                    state.tokens.prev.fud();
                    advance(")");
                }

                if (state.tokens.next.id === "(end)")
                    error("E006", state.tokens.curr);

                var isDangerous =
                    state.option.asi &&
                    state.tokens.prev.line !== startLine(state.tokens.curr) &&
                    _.contains(["]", ")"], state.tokens.prev.id) &&
                    _.contains(["[", "("], state.tokens.curr.id);

                if (isDangerous)
                    warning("W014", state.tokens.curr, state.tokens.curr.id);

                advance();

                if (initial) {
                    state.funct["(verb)"] = state.tokens.curr.value;
                    state.tokens.curr.beginsStmt = true;
                }

                if (initial === true && state.tokens.curr.fud) {
                    left = state.tokens.curr.fud();
                } else {
                    if (state.tokens.curr.nud) {
                        left = state.tokens.curr.nud();
                    } else {
                        error("E030", state.tokens.curr, state.tokens.curr.id);
                    }
                    while ((rbp < state.tokens.next.lbp || state.tokens.next.type === "(template)") &&
                    !isEndOfExpr()) {
                        isArray = state.tokens.curr.value === "Array";
                        isObject = state.tokens.curr.value === "Object";
                        if (left && (left.value || (left.first && left.first.value))) {
                            if (left.value !== "new" ||
                                (left.first && left.first.value && left.first.value === ".")) {
                                isArray = false;
                                if (left.value !== state.tokens.curr.value) {
                                    isObject = false;
                                }
                            }
                        }

                        advance();

                        if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") {
                            warning("W009", state.tokens.curr);
                        }

                        if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") {
                            warning("W010", state.tokens.curr);
                        }

                        if (left && state.tokens.curr.led) {
                            left = state.tokens.curr.led(left);
                        } else {
                            error("E033", state.tokens.curr, state.tokens.curr.id);
                        }
                    }
                }
                if (isLetExpr) {
                    state.funct["(scope)"].unstack();
                }

                state.nameStack.pop();

                return left;
            }

            function startLine(token) {
                return token.startLine || token.line;
            }

            function nobreaknonadjacent(left, right) {
                left = left || state.tokens.curr;
                right = right || state.tokens.next;
                if (!state.option.laxbreak && left.line !== startLine(right)) {
                    warning("W014", right, right.value);
                }
            }

            function nolinebreak(t) {
                t = t || state.tokens.curr;
                if (t.line !== startLine(state.tokens.next)) {
                    warning("E022", t, t.value);
                }
            }

            function nobreakcomma(left, right) {
                if (left.line !== startLine(right)) {
                    if (!state.option.laxcomma) {
                        if (comma.first) {
                            warning("I001");
                            comma.first = false;
                        }
                        warning("W014", left, right.value);
                    }
                }
            }

            function comma(opts) {
                opts = opts || {};

                if (!opts.peek) {
                    nobreakcomma(state.tokens.curr, state.tokens.next);
                    advance(",");
                } else {
                    nobreakcomma(state.tokens.prev, state.tokens.curr);
                }

                if (state.tokens.next.identifier && !(opts.property && state.inES5())) {
                    switch (state.tokens.next.value) {
                        case "break":
                        case "case":
                        case "catch":
                        case "continue":
                        case "default":
                        case "do":
                        case "else":
                        case "finally":
                        case "for":
                        case "if":
                        case "in":
                        case "instanceof":
                        case "return":
                        case "switch":
                        case "throw":
                        case "try":
                        case "var":
                        case "let":
                        case "while":
                        case "with":
                            error("E024", state.tokens.next, state.tokens.next.value);
                            return false;
                    }
                }

                if (state.tokens.next.type === "(punctuator)") {
                    switch (state.tokens.next.value) {
                        case "}":
                        case "]":
                        case ",":
                            if (opts.allowTrailing) {
                                return true;
                            }
                        case ")":
                            error("E024", state.tokens.next, state.tokens.next.value);
                            return false;
                    }
                }
                return true;
            }

            function symbol(s, p) {
                var x = state.syntax[s];
                if (!x || typeof x !== "object") {
                    state.syntax[s] = x = {
                        id: s,
                        lbp: p,
                        value: s
                    };
                }
                return x;
            }

            function delim(s) {
                var x = symbol(s, 0);
                x.delim = true;
                return x;
            }

            function stmt(s, f) {
                var x = delim(s);
                x.identifier = x.reserved = true;
                x.fud = f;
                return x;
            }

            function blockstmt(s, f) {
                var x = stmt(s, f);
                x.block = true;
                return x;
            }

            function reserveName(x) {
                var c = x.id.charAt(0);
                if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) {
                    x.identifier = x.reserved = true;
                }
                return x;
            }

            function prefix(s, f) {
                var x = symbol(s, 150);
                reserveName(x);

                x.nud = (typeof f === "function") ? f : function() {
                        this.arity = "unary";
                        this.right = expression(150);

                        if (this.id === "++" || this.id === "--") {
                            if (state.option.plusplus) {
                                warning("W016", this, this.id);
                            } else if (this.right && (!this.right.identifier || isReserved(this.right)) &&
                                this.right.id !== "." && this.right.id !== "[") {
                                warning("W017", this);
                            }

                            if (this.right && this.right.isMetaProperty) {
                                error("E031", this);
                            } else if (this.right && this.right.identifier) {
                                state.funct["(scope)"].block.modify(this.right.value, this);
                            }
                        }

                        return this;
                    };

                return x;
            }

            function type(s, f) {
                var x = delim(s);
                x.type = s;
                x.nud = f;
                return x;
            }

            function reserve(name, func) {
                var x = type(name, func);
                x.identifier = true;
                x.reserved = true;
                return x;
            }

            function FutureReservedWord(name, meta) {
                var x = type(name, (meta && meta.nud) || function() {
                        return this;
                    });

                meta = meta || {};
                meta.isFutureReservedWord = true;

                x.value = name;
                x.identifier = true;
                x.reserved = true;
                x.meta = meta;

                return x;
            }

            function reservevar(s, v) {
                return reserve(s, function() {
                    if (typeof v === "function") {
                        v(this);
                    }
                    return this;
                });
            }

            function infix(s, f, p, w) {
                var x = symbol(s, p);
                reserveName(x);
                x.infix = true;
                x.led = function(left) {
                    if (!w) {
                        nobreaknonadjacent(state.tokens.prev, state.tokens.curr);
                    }
                    if ((s === "in" || s === "instanceof") && left.id === "!") {
                        warning("W018", left, "!");
                    }
                    if (typeof f === "function") {
                        return f(left, this);
                    } else {
                        this.left = left;
                        this.right = expression(p);
                        return this;
                    }
                };
                return x;
            }

            function application(s) {
                var x = symbol(s, 42);

                x.led = function(left) {
                    nobreaknonadjacent(state.tokens.prev, state.tokens.curr);

                    this.left = left;
                    this.right = doFunction({ type: "arrow", loneArg: left });
                    return this;
                };
                return x;
            }

            function relation(s, f) {
                var x = symbol(s, 100);

                x.led = function(left) {
                    nobreaknonadjacent(state.tokens.prev, state.tokens.curr);
                    this.left = left;
                    var right = this.right = expression(100);

                    if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) {
                        warning("W019", this);
                    } else if (f) {
                        f.apply(this, [left, right]);
                    }

                    if (!left || !right) {
                        quit("E041", state.tokens.curr.line);
                    }

                    if (left.id === "!") {
                        warning("W018", left, "!");
                    }

                    if (right.id === "!") {
                        warning("W018", right, "!");
                    }

                    return this;
                };
                return x;
            }

            function isPoorRelation(node) {
                return node &&
                    ((node.type === "(number)" && +node.value === 0) ||
                    (node.type === "(string)" && node.value === "") ||
                    (node.type === "null" && !state.option.eqnull) ||
                    node.type === "true" ||
                    node.type === "false" ||
                    node.type === "undefined");
            }

            var typeofValues = {};
            typeofValues.legacy = [
                "xml",
                "unknown"
            ];
            typeofValues.es3 = [
                "undefined", "boolean", "number", "string", "function", "object",
            ];
            typeofValues.es3 = typeofValues.es3.concat(typeofValues.legacy);
            typeofValues.es6 = typeofValues.es3.concat("symbol");
            function isTypoTypeof(left, right, state) {
                var values;

                if (state.option.notypeof)
                    return false;

                if (!left || !right)
                    return false;

                values = state.inES6() ? typeofValues.es6 : typeofValues.es3;

                if (right.type === "(identifier)" && right.value === "typeof" && left.type === "(string)")
                    return !_.contains(values, left.value);

                return false;
            }

            function isGlobalEval(left, state) {
                var isGlobal = false;
                if (left.type === "this" && state.funct["(context)"] === null) {
                    isGlobal = true;
                }
                else if (left.type === "(identifier)") {
                    if (state.option.node && left.value === "global") {
                        isGlobal = true;
                    }

                    else if (state.option.browser && (left.value === "window" || left.value === "document")) {
                        isGlobal = true;
                    }
                }

                return isGlobal;
            }

            function findNativePrototype(left) {
                var natives = [
                    "Array", "ArrayBuffer", "Boolean", "Collator", "DataView", "Date",
                    "DateTimeFormat", "Error", "EvalError", "Float32Array", "Float64Array",
                    "Function", "Infinity", "Intl", "Int16Array", "Int32Array", "Int8Array",
                    "Iterator", "Number", "NumberFormat", "Object", "RangeError",
                    "ReferenceError", "RegExp", "StopIteration", "String", "SyntaxError",
                    "TypeError", "Uint16Array", "Uint32Array", "Uint8Array", "Uint8ClampedArray",
                    "URIError"
                ];

                function walkPrototype(obj) {
                    if (typeof obj !== "object") return;
                    return obj.right === "prototype" ? obj : walkPrototype(obj.left);
                }

                function walkNative(obj) {
                    while (!obj.identifier && typeof obj.left === "object")
                        obj = obj.left;

                    if (obj.identifier && natives.indexOf(obj.value) >= 0)
                        return obj.value;
                }

                var prototype = walkPrototype(left);
                if (prototype) return walkNative(prototype);
            }
            function checkLeftSideAssign(left, assignToken, options) {

                var allowDestructuring = options && options.allowDestructuring;

                assignToken = assignToken || left;

                if (state.option.freeze) {
                    var nativeObject = findNativePrototype(left);
                    if (nativeObject)
                        warning("W121", left, nativeObject);
                }

                if (left.identifier && !left.isMetaProperty) {
                    state.funct["(scope)"].block.reassign(left.value, left);
                }

                if (left.id === ".") {
                    if (!left.left || left.left.value === "arguments" && !state.isStrict()) {
                        warning("E031", assignToken);
                    }

                    state.nameStack.set(state.tokens.prev);
                    return true;
                } else if (left.id === "{" || left.id === "[") {
                    if (allowDestructuring && state.tokens.curr.left.destructAssign) {
                        state.tokens.curr.left.destructAssign.forEach(function(t) {
                            if (t.id) {
                                state.funct["(scope)"].block.modify(t.id, t.token);
                            }
                        });
                    } else {
                        if (left.id === "{" || !left.left) {
                            warning("E031", assignToken);
                        } else if (left.left.value === "arguments" && !state.isStrict()) {
                            warning("E031", assignToken);
                        }
                    }

                    if (left.id === "[") {
                        state.nameStack.set(left.right);
                    }

                    return true;
                } else if (left.isMetaProperty) {
                    error("E031", assignToken);
                    return true;
                } else if (left.identifier && !isReserved(left)) {
                    if (state.funct["(scope)"].labeltype(left.value) === "exception") {
                        warning("W022", left);
                    }
                    state.nameStack.set(left);
                    return true;
                }

                if (left === state.syntax["function"]) {
                    warning("W023", state.tokens.curr);
                }

                return false;
            }

            function assignop(s, f, p) {
                var x = infix(s, typeof f === "function" ? f : function(left, that) {
                        that.left = left;

                        if (left && checkLeftSideAssign(left, that, { allowDestructuring: true })) {
                            that.right = expression(10);
                            return that;
                        }

                        error("E031", that);
                    }, p);

                x.exps = true;
                x.assign = true;
                return x;
            }


            function bitwise(s, f, p) {
                var x = symbol(s, p);
                reserveName(x);
                x.led = (typeof f === "function") ? f : function(left) {
                        if (state.option.bitwise) {
                            warning("W016", this, this.id);
                        }
                        this.left = left;
                        this.right = expression(p);
                        return this;
                    };
                return x;
            }

            function bitwiseassignop(s) {
                return assignop(s, function(left, that) {
                    if (state.option.bitwise) {
                        warning("W016", that, that.id);
                    }

                    if (left && checkLeftSideAssign(left, that)) {
                        that.right = expression(10);
                        return that;
                    }
                    error("E031", that);
                }, 20);
            }

            function suffix(s) {
                var x = symbol(s, 150);

                x.led = function(left) {
                    if (state.option.plusplus) {
                        warning("W016", this, this.id);
                    } else if ((!left.identifier || isReserved(left)) && left.id !== "." && left.id !== "[") {
                        warning("W017", this);
                    }

                    if (left.isMetaProperty) {
                        error("E031", this);
                    } else if (left && left.identifier) {
                        state.funct["(scope)"].block.modify(left.value, left);
                    }

                    this.left = left;
                    return this;
                };
                return x;
            }

            function optionalidentifier(fnparam, prop, preserve) {
                if (!state.tokens.next.identifier) {
                    return;
                }

                if (!preserve) {
                    advance();
                }

                var curr = state.tokens.curr;
                var val  = state.tokens.curr.value;

                if (!isReserved(curr)) {
                    return val;
                }

                if (prop) {
                    if (state.inES5()) {
                        return val;
                    }
                }

                if (fnparam && val === "undefined") {
                    return val;
                }

                warning("W024", state.tokens.curr, state.tokens.curr.id);
                return val;
            }
            function identifier(fnparam, prop) {
                var i = optionalidentifier(fnparam, prop, false);
                if (i) {
                    return i;
                }
                if (state.tokens.next.value === "...") {
                    if (!state.inES6(true)) {
                        warning("W119", state.tokens.next, "spread/rest operator", "6");
                    }
                    advance();

                    if (checkPunctuator(state.tokens.next, "...")) {
                        warning("E024", state.tokens.next, "...");
                        while (checkPunctuator(state.tokens.next, "...")) {
                            advance();
                        }
                    }

                    if (!state.tokens.next.identifier) {
                        warning("E024", state.tokens.curr, "...");
                        return;
                    }

                    return identifier(fnparam, prop);
                } else {
                    error("E030", state.tokens.next, state.tokens.next.value);
                    if (state.tokens.next.id !== ";") {
                        advance();
                    }
                }
            }


            function reachable(controlToken) {
                var i = 0, t;
                if (state.tokens.next.id !== ";" || controlToken.inBracelessBlock) {
                    return;
                }
                for (;;) {
                    do {
                        t = peek(i);
                        i += 1;
                    } while (t.id !== "(end)" && t.id === "(comment)");

                    if (t.reach) {
                        return;
                    }
                    if (t.id !== "(endline)") {
                        if (t.id === "function") {
                            if (state.option.latedef === true) {
                                warning("W026", t);
                            }
                            break;
                        }

                        warning("W027", t, t.value, controlToken.value);
                        break;
                    }
                }
            }

            function parseFinalSemicolon() {
                if (state.tokens.next.id !== ";") {
                    if (state.tokens.next.isUnclosed) return advance();

                    var sameLine = startLine(state.tokens.next) === state.tokens.curr.line &&
                        state.tokens.next.id !== "(end)";
                    var blockEnd = checkPunctuator(state.tokens.next, "}");

                    if (sameLine && !blockEnd) {
                        errorAt("E058", state.tokens.curr.line, state.tokens.curr.character);
                    } else if (!state.option.asi) {
                        if ((blockEnd && !state.option.lastsemic) || !sameLine) {
                            warningAt("W033", state.tokens.curr.line, state.tokens.curr.character);
                        }
                    }
                } else {
                    advance(";");
                }
            }

            function statement() {
                var i = indent, r, t = state.tokens.next, hasOwnScope = false;

                if (t.id === ";") {
                    advance(";");
                    return;
                }
                var res = isReserved(t);

                if (res && t.meta && t.meta.isFutureReservedWord && peek().id === ":") {
                    warning("W024", t, t.id);
                    res = false;
                }

                if (t.identifier && !res && peek().id === ":") {
                    advance();
                    advance(":");

                    hasOwnScope = true;
                    state.funct["(scope)"].stack();
                    state.funct["(scope)"].block.addBreakLabel(t.value, { token: state.tokens.curr });

                    if (!state.tokens.next.labelled && state.tokens.next.value !== "{") {
                        warning("W028", state.tokens.next, t.value, state.tokens.next.value);
                    }

                    state.tokens.next.label = t.value;
                    t = state.tokens.next;
                }

                if (t.id === "{") {
                    var iscase = (state.funct["(verb)"] === "case" && state.tokens.curr.value === ":");
                    block(true, true, false, false, iscase);
                    return;
                }

                r = expression(0, true);

                if (r && !(r.identifier && r.value === "function") &&
                    !(r.type === "(punctuator)" && r.left &&
                    r.left.identifier && r.left.value === "function")) {
                    if (!state.isStrict() &&
                        state.option.strict === "global") {
                        warning("E007");
                    }
                }

                if (!t.block) {
                    if (!state.option.expr && (!r || !r.exps)) {
                        warning("W030", state.tokens.curr);
                    } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") {
                        warning("W031", t);
                    }
                    parseFinalSemicolon();
                }

                indent = i;
                if (hasOwnScope) {
                    state.funct["(scope)"].unstack();
                }
                return r;
            }


            function statements() {
                var a = [], p;

                while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") {
                    if (state.tokens.next.id === ";") {
                        p = peek();

                        if (!p || (p.id !== "(" && p.id !== "[")) {
                            warning("W032");
                        }

                        advance(";");
                    } else {
                        a.push(statement());
                    }
                }
                return a;
            }
            function directives() {
                var i, p, pn;

                while (state.tokens.next.id === "(string)") {
                    p = peek(0);
                    if (p.id === "(endline)") {
                        i = 1;
                        do {
                            pn = peek(i++);
                        } while (pn.id === "(endline)");
                        if (pn.id === ";") {
                            p = pn;
                        } else if (pn.value === "[" || pn.value === ".") {
                            break;
                        } else if (!state.option.asi || pn.value === "(") {
                            warning("W033", state.tokens.next);
                        }
                    } else if (p.id === "." || p.id === "[") {
                        break;
                    } else if (p.id !== ";") {
                        warning("W033", p);
                    }

                    advance();
                    var directive = state.tokens.curr.value;
                    if (state.directive[directive] ||
                        (directive === "use strict" && state.option.strict === "implied")) {
                        warning("W034", state.tokens.curr, directive);
                    }
                    state.directive[directive] = true;

                    if (p.id === ";") {
                        advance(";");
                    }
                }

                if (state.isStrict()) {
                    if (!state.option["(explicitNewcap)"]) {
                        state.option.newcap = true;
                    }
                    state.option.undef = true;
                }
            }
            function block(ordinary, stmt, isfunc, isfatarrow, iscase) {
                var a,
                    b = inblock,
                    old_indent = indent,
                    m,
                    t,
                    line,
                    d;

                inblock = ordinary;

                t = state.tokens.next;

                var metrics = state.funct["(metrics)"];
                metrics.nestedBlockDepth += 1;
                metrics.verifyMaxNestedBlockDepthPerFunction();

                if (state.tokens.next.id === "{") {
                    advance("{");
                    state.funct["(scope)"].stack();

                    line = state.tokens.curr.line;
                    if (state.tokens.next.id !== "}") {
                        indent += state.option.indent;
                        while (!ordinary && state.tokens.next.from > indent) {
                            indent += state.option.indent;
                        }

                        if (isfunc) {
                            m = {};
                            for (d in state.directive) {
                                if (_.has(state.directive, d)) {
                                    m[d] = state.directive[d];
                                }
                            }
                            directives();

                            if (state.option.strict && state.funct["(context)"]["(global)"]) {
                                if (!m["use strict"] && !state.isStrict()) {
                                    warning("E007");
                                }
                            }
                        }

                        a = statements();

                        metrics.statementCount += a.length;

                        indent -= state.option.indent;
                    }

                    advance("}", t);

                    if (isfunc) {
                        state.funct["(scope)"].validateParams();
                        if (m) {
                            state.directive = m;
                        }
                    }

                    state.funct["(scope)"].unstack();

                    indent = old_indent;
                } else if (!ordinary) {
                    if (isfunc) {
                        state.funct["(scope)"].stack();

                        m = {};
                        if (stmt && !isfatarrow && !state.inMoz()) {
                            error("W118", state.tokens.curr, "function closure expressions");
                        }

                        if (!stmt) {
                            for (d in state.directive) {
                                if (_.has(state.directive, d)) {
                                    m[d] = state.directive[d];
                                }
                            }
                        }
                        expression(10);

                        if (state.option.strict && state.funct["(context)"]["(global)"]) {
                            if (!m["use strict"] && !state.isStrict()) {
                                warning("E007");
                            }
                        }

                        state.funct["(scope)"].unstack();
                    } else {
                        error("E021", state.tokens.next, "{", state.tokens.next.value);
                    }
                } else {
                    state.funct["(noblockscopedvar)"] = state.tokens.next.id !== "for";
                    state.funct["(scope)"].stack();

                    if (!stmt || state.option.curly) {
                        warning("W116", state.tokens.next, "{", state.tokens.next.value);
                    }

                    state.tokens.next.inBracelessBlock = true;
                    indent += state.option.indent;
                    a = [statement()];
                    indent -= state.option.indent;

                    state.funct["(scope)"].unstack();
                    delete state.funct["(noblockscopedvar)"];
                }
                switch (state.funct["(verb)"]) {
                    case "break":
                    case "continue":
                    case "return":
                    case "throw":
                        if (iscase) {
                            break;
                        }
                    default:
                        state.funct["(verb)"] = null;
                }

                inblock = b;
                if (ordinary && state.option.noempty && (!a || a.length === 0)) {
                    warning("W035", state.tokens.prev);
                }
                metrics.nestedBlockDepth -= 1;
                return a;
            }


            function countMember(m) {
                if (membersOnly && typeof membersOnly[m] !== "boolean") {
                    warning("W036", state.tokens.curr, m);
                }
                if (typeof member[m] === "number") {
                    member[m] += 1;
                } else {
                    member[m] = 1;
                }
            }

            type("(number)", function() {
                return this;
            });

            type("(string)", function() {
                return this;
            });

            state.syntax["(identifier)"] = {
                type: "(identifier)",
                lbp: 0,
                identifier: true,

                nud: function() {
                    var v = this.value;
                    if (state.tokens.next.id === "=>") {
                        return this;
                    }

                    if (!state.funct["(comparray)"].check(v)) {
                        state.funct["(scope)"].block.use(v, state.tokens.curr);
                    }
                    return this;
                },

                led: function() {
                    error("E033", state.tokens.next, state.tokens.next.value);
                }
            };

            var baseTemplateSyntax = {
                lbp: 0,
                identifier: false,
                template: true,
            };
            state.syntax["(template)"] = _.extend({
                type: "(template)",
                nud: doTemplateLiteral,
                led: doTemplateLiteral,
                noSubst: false
            }, baseTemplateSyntax);

            state.syntax["(template middle)"] = _.extend({
                type: "(template middle)",
                middle: true,
                noSubst: false
            }, baseTemplateSyntax);

            state.syntax["(template tail)"] = _.extend({
                type: "(template tail)",
                tail: true,
                noSubst: false
            }, baseTemplateSyntax);

            state.syntax["(no subst template)"] = _.extend({
                type: "(template)",
                nud: doTemplateLiteral,
                led: doTemplateLiteral,
                noSubst: true,
                tail: true // mark as tail, since it's always the last component
            }, baseTemplateSyntax);

            type("(regexp)", function() {
                return this;
            });

            delim("(endline)");
            delim("(begin)");
            delim("(end)").reach = true;
            delim("(error)").reach = true;
            delim("}").reach = true;
            delim(")");
            delim("]");
            delim("\"").reach = true;
            delim("'").reach = true;
            delim(";");
            delim(":").reach = true;
            delim("#");

            reserve("else");
            reserve("case").reach = true;
            reserve("catch");
            reserve("default").reach = true;
            reserve("finally");
            reservevar("arguments", function(x) {
                if (state.isStrict() && state.funct["(global)"]) {
                    warning("E008", x);
                }
            });
            reservevar("eval");
            reservevar("false");
            reservevar("Infinity");
            reservevar("null");
            reservevar("this", function(x) {
                if (state.isStrict() && !isMethod() &&
                    !state.option.validthis && ((state.funct["(statement)"] &&
                    state.funct["(name)"].charAt(0) > "Z") || state.funct["(global)"])) {
                    warning("W040", x);
                }
            });
            reservevar("true");
            reservevar("undefined");

            assignop("=", "assign", 20);
            assignop("+=", "assignadd", 20);
            assignop("-=", "assignsub", 20);
            assignop("*=", "assignmult", 20);
            assignop("/=", "assigndiv", 20).nud = function() {
                error("E014");
            };
            assignop("%=", "assignmod", 20);

            bitwiseassignop("&=");
            bitwiseassignop("|=");
            bitwiseassignop("^=");
            bitwiseassignop("<<=");
            bitwiseassignop(">>=");
            bitwiseassignop(">>>=");
            infix(",", function(left, that) {
                var expr;
                that.exprs = [left];

                if (state.option.nocomma) {
                    warning("W127");
                }

                if (!comma({ peek: true })) {
                    return that;
                }
                while (true) {
                    if (!(expr = expression(10))) {
                        break;
                    }
                    that.exprs.push(expr);
                    if (state.tokens.next.value !== "," || !comma()) {
                        break;
                    }
                }
                return that;
            }, 10, true);

            infix("?", function(left, that) {
                increaseComplexityCount();
                that.left = left;
                that.right = expression(10);
                advance(":");
                that["else"] = expression(10);
                return that;
            }, 30);

            var orPrecendence = 40;
            infix("||", function(left, that) {
                increaseComplexityCount();
                that.left = left;
                that.right = expression(orPrecendence);
                return that;
            }, orPrecendence);
            infix("&&", "and", 50);
            bitwise("|", "bitor", 70);
            bitwise("^", "bitxor", 80);
            bitwise("&", "bitand", 90);
            relation("==", function(left, right) {
                var eqnull = state.option.eqnull &&
                    ((left && left.value) === "null" || (right && right.value) === "null");

                switch (true) {
                    case !eqnull && state.option.eqeqeq:
                        this.from = this.character;
                        warning("W116", this, "===", "==");
                        break;
                    case isPoorRelation(left):
                        warning("W041", this, "===", left.value);
                        break;
                    case isPoorRelation(right):
                        warning("W041", this, "===", right.value);
                        break;
                    case isTypoTypeof(right, left, state):
                        warning("W122", this, right.value);
                        break;
                    case isTypoTypeof(left, right, state):
                        warning("W122", this, left.value);
                        break;
                }

                return this;
            });
            relation("===", function(left, right) {
                if (isTypoTypeof(right, left, state)) {
                    warning("W122", this, right.value);
                } else if (isTypoTypeof(left, right, state)) {
                    warning("W122", this, left.value);
                }
                return this;
            });
            relation("!=", function(left, right) {
                var eqnull = state.option.eqnull &&
                    ((left && left.value) === "null" || (right && right.value) === "null");

                if (!eqnull && state.option.eqeqeq) {
                    this.from = this.character;
                    warning("W116", this, "!==", "!=");
                } else if (isPoorRelation(left)) {
                    warning("W041", this, "!==", left.value);
                } else if (isPoorRelation(right)) {
                    warning("W041", this, "!==", right.value);
                } else if (isTypoTypeof(right, left, state)) {
                    warning("W122", this, right.value);
                } else if (isTypoTypeof(left, right, state)) {
                    warning("W122", this, left.value);
                }
                return this;
            });
            relation("!==", function(left, right) {
                if (isTypoTypeof(right, left, state)) {
                    warning("W122", this, right.value);
                } else if (isTypoTypeof(left, right, state)) {
                    warning("W122", this, left.value);
                }
                return this;
            });
            relation("<");
            relation(">");
            relation("<=");
            relation(">=");
            bitwise("<<", "shiftleft", 120);
            bitwise(">>", "shiftright", 120);
            bitwise(">>>", "shiftrightunsigned", 120);
            infix("in", "in", 120);
            infix("instanceof", "instanceof", 120);
            infix("+", function(left, that) {
                var right;
                that.left = left;
                that.right = right = expression(130);

                if (left && right && left.id === "(string)" && right.id === "(string)") {
                    left.value += right.value;
                    left.character = right.character;
                    if (!state.option.scripturl && reg.javascriptURL.test(left.value)) {
                        warning("W050", left);
                    }
                    return left;
                }

                return that;
            }, 130);
            prefix("+", "num");
            prefix("+++", function() {
                warning("W007");
                this.arity = "unary";
                this.right = expression(150);
                return this;
            });
            infix("+++", function(left) {
                warning("W007");
                this.left = left;
                this.right = expression(130);
                return this;
            }, 130);
            infix("-", "sub", 130);
            prefix("-", "neg");
            prefix("---", function() {
                warning("W006");
                this.arity = "unary";
                this.right = expression(150);
                return this;
            });
            infix("---", function(left) {
                warning("W006");
                this.left = left;
                this.right = expression(130);
                return this;
            }, 130);
            infix("*", "mult", 140);
            infix("/", "div", 140);
            infix("%", "mod", 140);

            suffix("++");
            prefix("++", "preinc");
            state.syntax["++"].exps = true;

            suffix("--");
            prefix("--", "predec");
            state.syntax["--"].exps = true;
            prefix("delete", function() {
                var p = expression(10);
                if (!p) {
                    return this;
                }

                if (p.id !== "." && p.id !== "[") {
                    warning("W051");
                }
                this.first = p;
                if (p.identifier && !state.isStrict()) {
                    p.forgiveUndef = true;
                }
                return this;
            }).exps = true;

            prefix("~", function() {
                if (state.option.bitwise) {
                    warning("W016", this, "~");
                }
                this.arity = "unary";
                this.right = expression(150);
                return this;
            });

            prefix("...", function() {
                if (!state.inES6(true)) {
                    warning("W119", this, "spread/rest operator", "6");
                }
                if (!state.tokens.next.identifier &&
                    state.tokens.next.type !== "(string)" &&
                    !checkPunctuators(state.tokens.next, ["[", "("])) {

                    error("E030", state.tokens.next, state.tokens.next.value);
                }
                expression(150);
                return this;
            });

            prefix("!", function() {
                this.arity = "unary";
                this.right = expression(150);

                if (!this.right) { // '!' followed by nothing? Give up.
                    quit("E041", this.line || 0);
                }

                if (bang[this.right.id] === true) {
                    warning("W018", this, "!");
                }
                return this;
            });

            prefix("typeof", (function() {
                var p = expression(150);
                this.first = this.right = p;

                if (!p) { // 'typeof' followed by nothing? Give up.
                    quit("E041", this.line || 0, this.character || 0);
                }
                if (p.identifier) {
                    p.forgiveUndef = true;
                }
                return this;
            }));
            prefix("new", function() {
                var mp = metaProperty("target", function() {
                    if (!state.inES6(true)) {
                        warning("W119", state.tokens.prev, "new.target", "6");
                    }
                    var inFunction, c = state.funct;
                    while (c) {
                        inFunction = !c["(global)"];
                        if (!c["(arrow)"]) { break; }
                        c = c["(context)"];
                    }
                    if (!inFunction) {
                        warning("W136", state.tokens.prev, "new.target");
                    }
                });
                if (mp) { return mp; }

                var c = expression(155), i;
                if (c && c.id !== "function") {
                    if (c.identifier) {
                        c["new"] = true;
                        switch (c.value) {
                            case "Number":
                            case "String":
                            case "Boolean":
                            case "Math":
                            case "JSON":
                                warning("W053", state.tokens.prev, c.value);
                                break;
                            case "Symbol":
                                if (state.inES6()) {
                                    warning("W053", state.tokens.prev, c.value);
                                }
                                break;
                            case "Function":
                                if (!state.option.evil) {
                                    warning("W054");
                                }
                                break;
                            case "Date":
                            case "RegExp":
                            case "this":
                                break;
                            default:
                                if (c.id !== "function") {
                                    i = c.value.substr(0, 1);
                                    if (state.option.newcap && (i < "A" || i > "Z") &&
                                        !state.funct["(scope)"].isPredefined(c.value)) {
                                        warning("W055", state.tokens.curr);
                                    }
                                }
                        }
                    } else {
                        if (c.id !== "." && c.id !== "[" && c.id !== "(") {
                            warning("W056", state.tokens.curr);
                        }
                    }
                } else {
                    if (!state.option.supernew)
                        warning("W057", this);
                }
                if (state.tokens.next.id !== "(" && !state.option.supernew) {
                    warning("W058", state.tokens.curr, state.tokens.curr.value);
                }
                this.first = this.right = c;
                return this;
            });
            state.syntax["new"].exps = true;

            prefix("void").exps = true;

            infix(".", function(left, that) {
                var m = identifier(false, true);

                if (typeof m === "string") {
                    countMember(m);
                }

                that.left = left;
                that.right = m;

                if (m && m === "hasOwnProperty" && state.tokens.next.value === "=") {
                    warning("W001");
                }

                if (left && left.value === "arguments" && (m === "callee" || m === "caller")) {
                    if (state.option.noarg)
                        warning("W059", left, m);
                    else if (state.isStrict())
                        error("E008");
                } else if (!state.option.evil && left && left.value === "document" &&
                    (m === "write" || m === "writeln")) {
                    warning("W060", left);
                }

                if (!state.option.evil && (m === "eval" || m === "execScript")) {
                    if (isGlobalEval(left, state)) {
                        warning("W061");
                    }
                }

                return that;
            }, 160, true);

            infix("(", function(left, that) {
                if (state.option.immed && left && !left.immed && left.id === "function") {
                    warning("W062");
                }

                var n = 0;
                var p = [];

                if (left) {
                    if (left.type === "(identifier)") {
                        if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
                            if ("Array Number String Boolean Date Object Error Symbol".indexOf(left.value) === -1) {
                                if (left.value === "Math") {
                                    warning("W063", left);
                                } else if (state.option.newcap) {
                                    warning("W064", left);
                                }
                            }
                        }
                    }
                }

                if (state.tokens.next.id !== ")") {
                    for (;;) {
                        p[p.length] = expression(10);
                        n += 1;
                        if (state.tokens.next.id !== ",") {
                            break;
                        }
                        comma();
                    }
                }

                advance(")");

                if (typeof left === "object") {
                    if (!state.inES5() && left.value === "parseInt" && n === 1) {
                        warning("W065", state.tokens.curr);
                    }
                    if (!state.option.evil) {
                        if (left.value === "eval" || left.value === "Function" ||
                            left.value === "execScript") {
                            warning("W061", left);

                            if (p[0] && [0].id === "(string)") {
                                addInternalSrc(left, p[0].value);
                            }
                        } else if (p[0] && p[0].id === "(string)" &&
                            (left.value === "setTimeout" ||
                            left.value === "setInterval")) {
                            warning("W066", left);
                            addInternalSrc(left, p[0].value);
                        } else if (p[0] && p[0].id === "(string)" &&
                            left.value === "." &&
                            left.left.value === "window" &&
                            (left.right === "setTimeout" ||
                            left.right === "setInterval")) {
                            warning("W066", left);
                            addInternalSrc(left, p[0].value);
                        }
                    }
                    if (!left.identifier && left.id !== "." && left.id !== "[" && left.id !== "=>" &&
                        left.id !== "(" && left.id !== "&&" && left.id !== "||" && left.id !== "?" &&
                        !(state.inES6() && left["(name)"])) {
                        warning("W067", that);
                    }
                }

                that.left = left;
                return that;
            }, 155, true).exps = true;

            prefix("(", function() {
                var pn = state.tokens.next, pn1, i = -1;
                var ret, triggerFnExpr, first, last;
                var parens = 1;
                var opening = state.tokens.curr;
                var preceeding = state.tokens.prev;
                var isNecessary = !state.option.singleGroups;

                do {
                    if (pn.value === "(") {
                        parens += 1;
                    } else if (pn.value === ")") {
                        parens -= 1;
                    }

                    i += 1;
                    pn1 = pn;
                    pn = peek(i);
                } while (!(parens === 0 && pn1.value === ")") && pn.value !== ";" && pn.type !== "(end)");

                if (state.tokens.next.id === "function") {
                    triggerFnExpr = state.tokens.next.immed = true;
                }
                if (pn.value === "=>") {
                    return doFunction({ type: "arrow", parsedOpening: true });
                }

                var exprs = [];

                if (state.tokens.next.id !== ")") {
                    for (;;) {
                        exprs.push(expression(10));

                        if (state.tokens.next.id !== ",") {
                            break;
                        }

                        if (state.option.nocomma) {
                            warning("W127");
                        }

                        comma();
                    }
                }

                advance(")", this);
                if (state.option.immed && exprs[0] && exprs[0].id === "function") {
                    if (state.tokens.next.id !== "(" &&
                        state.tokens.next.id !== "." && state.tokens.next.id !== "[") {
                        warning("W068", this);
                    }
                }

                if (!exprs.length) {
                    return;
                }
                if (exprs.length > 1) {
                    ret = Object.create(state.syntax[","]);
                    ret.exprs = exprs;

                    first = exprs[0];
                    last = exprs[exprs.length - 1];

                    if (!isNecessary) {
                        isNecessary = preceeding.assign || preceeding.delim;
                    }
                } else {
                    ret = first = last = exprs[0];

                    if (!isNecessary) {
                        isNecessary =
                            (opening.beginsStmt && (ret.id === "{" || triggerFnExpr || isFunctor(ret))) ||
                            (triggerFnExpr &&
                            (!isEndOfExpr() || state.tokens.prev.id !== "}")) ||
                            (isFunctor(ret) && !isEndOfExpr()) ||
                            (ret.id === "{" && preceeding.id === "=>") ||
                            (ret.type === "(number)" &&
                            checkPunctuator(pn, ".") && /^\d+$/.test(ret.value));
                    }
                }

                if (ret) {
                    if (!isNecessary && (first.left || first.right || ret.exprs)) {
                        isNecessary =
                            (!isBeginOfExpr(preceeding) && first.lbp <= preceeding.lbp) ||
                            (!isEndOfExpr() && last.lbp < state.tokens.next.lbp);
                    }

                    if (!isNecessary) {
                        warning("W126", opening);
                    }

                    ret.paren = true;
                }

                return ret;
            });

            application("=>");

            infix("[", function(left, that) {
                var e = expression(10), s;
                if (e && e.type === "(string)") {
                    if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) {
                        if (isGlobalEval(left, state)) {
                            warning("W061");
                        }
                    }

                    countMember(e.value);
                    if (!state.option.sub && reg.identifier.test(e.value)) {
                        s = state.syntax[e.value];
                        if (!s || !isReserved(s)) {
                            warning("W069", state.tokens.prev, e.value);
                        }
                    }
                }
                advance("]", that);

                if (e && e.value === "hasOwnProperty" && state.tokens.next.value === "=") {
                    warning("W001");
                }

                that.left = left;
                that.right = e;
                return that;
            }, 160, true);

            function comprehensiveArrayExpression() {
                var res = {};
                res.exps = true;
                state.funct["(comparray)"].stack();
                var reversed = false;
                if (state.tokens.next.value !== "for") {
                    reversed = true;
                    if (!state.inMoz()) {
                        warning("W116", state.tokens.next, "for", state.tokens.next.value);
                    }
                    state.funct["(comparray)"].setState("use");
                    res.right = expression(10);
                }

                advance("for");
                if (state.tokens.next.value === "each") {
                    advance("each");
                    if (!state.inMoz()) {
                        warning("W118", state.tokens.curr, "for each");
                    }
                }
                advance("(");
                state.funct["(comparray)"].setState("define");
                res.left = expression(130);
                if (_.contains(["in", "of"], state.tokens.next.value)) {
                    advance();
                } else {
                    error("E045", state.tokens.curr);
                }
                state.funct["(comparray)"].setState("generate");
                expression(10);

                advance(")");
                if (state.tokens.next.value === "if") {
                    advance("if");
                    advance("(");
                    state.funct["(comparray)"].setState("filter");
                    res.filter = expression(10);
                    advance(")");
                }

                if (!reversed) {
                    state.funct["(comparray)"].setState("use");
                    res.right = expression(10);
                }

                advance("]");
                state.funct["(comparray)"].unstack();
                return res;
            }

            prefix("[", function() {
                var blocktype = lookupBlockType();
                if (blocktype.isCompArray) {
                    if (!state.option.esnext && !state.inMoz()) {
                        warning("W118", state.tokens.curr, "array comprehension");
                    }
                    return comprehensiveArrayExpression();
                } else if (blocktype.isDestAssign) {
                    this.destructAssign = destructuringPattern({ openingParsed: true, assignment: true });
                    return this;
                }
                var b = state.tokens.curr.line !== startLine(state.tokens.next);
                this.first = [];
                if (b) {
                    indent += state.option.indent;
                    if (state.tokens.next.from === indent + state.option.indent) {
                        indent += state.option.indent;
                    }
                }
                while (state.tokens.next.id !== "(end)") {
                    while (state.tokens.next.id === ",") {
                        if (!state.option.elision) {
                            if (!state.inES5()) {
                                warning("W070");
                            } else {
                                warning("W128");
                                do {
                                    advance(",");
                                } while (state.tokens.next.id === ",");
                                continue;
                            }
                        }
                        advance(",");
                    }

                    if (state.tokens.next.id === "]") {
                        break;
                    }

                    this.first.push(expression(10));
                    if (state.tokens.next.id === ",") {
                        comma({ allowTrailing: true });
                        if (state.tokens.next.id === "]" && !state.inES5()) {
                            warning("W070", state.tokens.curr);
                            break;
                        }
                    } else {
                        break;
                    }
                }
                if (b) {
                    indent -= state.option.indent;
                }
                advance("]", this);
                return this;
            });


            function isMethod() {
                return state.funct["(statement)"] && state.funct["(statement)"].type === "class" ||
                    state.funct["(context)"] && state.funct["(context)"]["(verb)"] === "class";
            }


            function isPropertyName(token) {
                return token.identifier || token.id === "(string)" || token.id === "(number)";
            }


            function propertyName(preserveOrToken) {
                var id;
                var preserve = true;
                if (typeof preserveOrToken === "object") {
                    id = preserveOrToken;
                } else {
                    preserve = preserveOrToken;
                    id = optionalidentifier(false, true, preserve);
                }

                if (!id) {
                    if (state.tokens.next.id === "(string)") {
                        id = state.tokens.next.value;
                        if (!preserve) {
                            advance();
                        }
                    } else if (state.tokens.next.id === "(number)") {
                        id = state.tokens.next.value.toString();
                        if (!preserve) {
                            advance();
                        }
                    }
                } else if (typeof id === "object") {
                    if (id.id === "(string)" || id.id === "(identifier)") id = id.value;
                    else if (id.id === "(number)") id = id.value.toString();
                }

                if (id === "hasOwnProperty") {
                    warning("W001");
                }

                return id;
            }
            function functionparams(options) {
                var next;
                var paramsIds = [];
                var ident;
                var tokens = [];
                var t;
                var pastDefault = false;
                var pastRest = false;
                var arity = 0;
                var loneArg = options && options.loneArg;

                if (loneArg && loneArg.identifier === true) {
                    state.funct["(scope)"].addParam(loneArg.value, loneArg);
                    return { arity: 1, params: [ loneArg.value ] };
                }

                next = state.tokens.next;

                if (!options || !options.parsedOpening) {
                    advance("(");
                }

                if (state.tokens.next.id === ")") {
                    advance(")");
                    return;
                }

                function addParam(addParamArgs) {
                    state.funct["(scope)"].addParam.apply(state.funct["(scope)"], addParamArgs);
                }

                for (;;) {
                    arity++;
                    var currentParams = [];

                    if (_.contains(["{", "["], state.tokens.next.id)) {
                        tokens = destructuringPattern();
                        for (t in tokens) {
                            t = tokens[t];
                            if (t.id) {
                                paramsIds.push(t.id);
                                currentParams.push([t.id, t.token]);
                            }
                        }
                    } else {
                        if (checkPunctuator(state.tokens.next, "...")) pastRest = true;
                        ident = identifier(true);
                        if (ident) {
                            paramsIds.push(ident);
                            currentParams.push([ident, state.tokens.curr]);
                        } else {
                            while (!checkPunctuators(state.tokens.next, [",", ")"])) advance();
                        }
                    }
                    if (pastDefault) {
                        if (state.tokens.next.id !== "=") {
                            error("W138", state.tokens.current);
                        }
                    }
                    if (state.tokens.next.id === "=") {
                        if (!state.inES6()) {
                            warning("W119", state.tokens.next, "default parameters", "6");
                        }
                        advance("=");
                        pastDefault = true;
                        expression(10);
                    }
                    currentParams.forEach(addParam);

                    if (state.tokens.next.id === ",") {
                        if (pastRest) {
                            warning("W131", state.tokens.next);
                        }
                        comma();
                    } else {
                        advance(")", next);
                        return { arity: arity, params: paramsIds };
                    }
                }
            }

            function functor(name, token, overwrites) {
                var funct = {
                    "(name)"      : name,
                    "(breakage)"  : 0,
                    "(loopage)"   : 0,
                    "(tokens)"    : {},
                    "(properties)": {},

                    "(catch)"     : false,
                    "(global)"    : false,

                    "(line)"      : null,
                    "(character)" : null,
                    "(metrics)"   : null,
                    "(statement)" : null,
                    "(context)"   : null,
                    "(scope)"     : null,
                    "(comparray)" : null,
                    "(generator)" : null,
                    "(arrow)"     : null,
                    "(params)"    : null
                };

                if (token) {
                    _.extend(funct, {
                        "(line)"     : token.line,
                        "(character)": token.character,
                        "(metrics)"  : createMetrics(token)
                    });
                }

                _.extend(funct, overwrites);

                if (funct["(context)"]) {
                    funct["(scope)"] = funct["(context)"]["(scope)"];
                    funct["(comparray)"]  = funct["(context)"]["(comparray)"];
                }

                return funct;
            }

            function isFunctor(token) {
                return "(scope)" in token;
            }
            function hasParsedCode(funct) {
                return funct["(global)"] && !funct["(verb)"];
            }

            function doTemplateLiteral(left) {
                var ctx = this.context;
                var noSubst = this.noSubst;
                var depth = this.depth;

                if (!noSubst) {
                    while (!end()) {
                        if (!state.tokens.next.template || state.tokens.next.depth > depth) {
                            expression(0); // should probably have different rbp?
                        } else {
                            advance();
                        }
                    }
                }

                return {
                    id: "(template)",
                    type: "(template)",
                    tag: left
                };

                function end() {
                    if (state.tokens.curr.template && state.tokens.curr.tail &&
                        state.tokens.curr.context === ctx) return true;
                    var complete = (state.tokens.next.template && state.tokens.next.tail &&
                    state.tokens.next.context === ctx);
                    if (complete) advance();
                    return complete || state.tokens.next.isUnclosed;
                }
            }
            function doFunction(options) {
                var f, token, name, statement, classExprBinding, isGenerator, isArrow, ignoreLoopFunc;
                var oldOption = state.option;
                var oldIgnored = state.ignored;

                if (options) {
                    name = options.name;
                    statement = options.statement;
                    classExprBinding = options.classExprBinding;
                    isGenerator = options.type === "generator";
                    isArrow = options.type === "arrow";
                    ignoreLoopFunc = options.ignoreLoopFunc;
                }

                state.option = Object.create(state.option);
                state.ignored = Object.create(state.ignored);

                state.funct = functor(name || state.nameStack.infer(), state.tokens.next, {
                    "(statement)": statement,
                    "(context)":   state.funct,
                    "(arrow)":     isArrow,
                    "(generator)": isGenerator
                });

                f = state.funct;
                token = state.tokens.curr;
                token.funct = state.funct;

                functions.push(state.funct);
                state.funct["(scope)"].stack("functionouter");
                var internallyAccessibleName = name || classExprBinding;
                if (internallyAccessibleName) {
                    state.funct["(scope)"].block.add(internallyAccessibleName,
                        classExprBinding ? "class" : "function", state.tokens.curr, false);
                }
                state.funct["(scope)"].stack("functionparams");

                var paramsInfo = functionparams(options);

                if (paramsInfo) {
                    state.funct["(params)"] = paramsInfo.params;
                    state.funct["(metrics)"].arity = paramsInfo.arity;
                    state.funct["(metrics)"].verifyMaxParametersPerFunction();
                } else {
                    state.funct["(metrics)"].arity = 0;
                }

                if (isArrow) {
                    if (!state.inES6(true)) {
                        warning("W119", state.tokens.curr, "arrow function syntax (=>)", "6");
                    }

                    if (!options.loneArg) {
                        advance("=>");
                    }
                }

                block(false, true, true, isArrow);

                if (!state.option.noyield && isGenerator &&
                    state.funct["(generator)"] !== "yielded") {
                    warning("W124", state.tokens.curr);
                }

                state.funct["(metrics)"].verifyMaxStatementsPerFunction();
                state.funct["(metrics)"].verifyMaxComplexityPerFunction();
                state.funct["(unusedOption)"] = state.option.unused;
                state.option = oldOption;
                state.ignored = oldIgnored;
                state.funct["(last)"] = state.tokens.curr.line;
                state.funct["(lastcharacter)"] = state.tokens.curr.character;
                state.funct["(scope)"].unstack(); // also does usage and label checks
                state.funct["(scope)"].unstack();

                state.funct = state.funct["(context)"];

                if (!ignoreLoopFunc && !state.option.loopfunc && state.funct["(loopage)"]) {
                    if (f["(isCapturing)"]) {
                        warning("W083", token);
                    }
                }

                return f;
            }

            function createMetrics(functionStartToken) {
                return {
                    statementCount: 0,
                    nestedBlockDepth: -1,
                    ComplexityCount: 1,
                    arity: 0,

                    verifyMaxStatementsPerFunction: function() {
                        if (state.option.maxstatements &&
                            this.statementCount > state.option.maxstatements) {
                            warning("W071", functionStartToken, this.statementCount);
                        }
                    },

                    verifyMaxParametersPerFunction: function() {
                        if (_.isNumber(state.option.maxparams) &&
                            this.arity > state.option.maxparams) {
                            warning("W072", functionStartToken, this.arity);
                        }
                    },

                    verifyMaxNestedBlockDepthPerFunction: function() {
                        if (state.option.maxdepth &&
                            this.nestedBlockDepth > 0 &&
                            this.nestedBlockDepth === state.option.maxdepth + 1) {
                            warning("W073", null, this.nestedBlockDepth);
                        }
                    },

                    verifyMaxComplexityPerFunction: function() {
                        var max = state.option.maxcomplexity;
                        var cc = this.ComplexityCount;
                        if (max && cc > max) {
                            warning("W074", functionStartToken, cc);
                        }
                    }
                };
            }

            function increaseComplexityCount() {
                state.funct["(metrics)"].ComplexityCount += 1;
            }

            function checkCondAssignment(expr) {
                var id, paren;
                if (expr) {
                    id = expr.id;
                    paren = expr.paren;
                    if (id === "," && (expr = expr.exprs[expr.exprs.length - 1])) {
                        id = expr.id;
                        paren = paren || expr.paren;
                    }
                }
                switch (id) {
                    case "=":
                    case "+=":
                    case "-=":
                    case "*=":
                    case "%=":
                    case "&=":
                    case "|=":
                    case "^=":
                    case "/=":
                        if (!paren && !state.option.boss) {
                            warning("W084");
                        }
                }
            }
            function checkProperties(props) {
                if (state.inES5()) {
                    for (var name in props) {
                        if (props[name] && props[name].setterToken && !props[name].getterToken) {
                            warning("W078", props[name].setterToken);
                        }
                    }
                }
            }

            function metaProperty(name, c) {
                if (checkPunctuator(state.tokens.next, ".")) {
                    var left = state.tokens.curr.id;
                    advance(".");
                    var id = identifier();
                    state.tokens.curr.isMetaProperty = true;
                    if (name !== id) {
                        error("E057", state.tokens.prev, left, id);
                    } else {
                        c();
                    }
                    return state.tokens.curr;
                }
            }

            (function(x) {
                x.nud = function() {
                    var b, f, i, p, t, isGeneratorMethod = false, nextVal;
                    var props = Object.create(null); // All properties, including accessors

                    b = state.tokens.curr.line !== startLine(state.tokens.next);
                    if (b) {
                        indent += state.option.indent;
                        if (state.tokens.next.from === indent + state.option.indent) {
                            indent += state.option.indent;
                        }
                    }

                    var blocktype = lookupBlockType();
                    if (blocktype.isDestAssign) {
                        this.destructAssign = destructuringPattern({ openingParsed: true, assignment: true });
                        return this;
                    }

                    for (;;) {
                        if (state.tokens.next.id === "}") {
                            break;
                        }

                        nextVal = state.tokens.next.value;
                        if (state.tokens.next.identifier &&
                            (peekIgnoreEOL().id === "," || peekIgnoreEOL().id === "}")) {
                            if (!state.inES6()) {
                                warning("W104", state.tokens.next, "object short notation", "6");
                            }
                            i = propertyName(true);
                            saveProperty(props, i, state.tokens.next);

                            expression(10);

                        } else if (peek().id !== ":" && (nextVal === "get" || nextVal === "set")) {
                            advance(nextVal);

                            if (!state.inES5()) {
                                error("E034");
                            }

                            i = propertyName();
                            if (!i && !state.inES6()) {
                                error("E035");
                            }
                            if (i) {
                                saveAccessor(nextVal, props, i, state.tokens.curr);
                            }

                            t = state.tokens.next;
                            f = doFunction();
                            p = f["(params)"];
                            if (nextVal === "get" && i && p) {
                                warning("W076", t, p[0], i);
                            } else if (nextVal === "set" && i && (!p || p.length !== 1)) {
                                warning("W077", t, i);
                            }
                        } else {
                            if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") {
                                if (!state.inES6()) {
                                    warning("W104", state.tokens.next, "generator functions", "6");
                                }
                                advance("*");
                                isGeneratorMethod = true;
                            } else {
                                isGeneratorMethod = false;
                            }

                            if (state.tokens.next.id === "[") {
                                i = computedPropertyName();
                                state.nameStack.set(i);
                            } else {
                                state.nameStack.set(state.tokens.next);
                                i = propertyName();
                                saveProperty(props, i, state.tokens.next);

                                if (typeof i !== "string") {
                                    break;
                                }
                            }

                            if (state.tokens.next.value === "(") {
                                if (!state.inES6()) {
                                    warning("W104", state.tokens.curr, "concise methods", "6");
                                }
                                doFunction({ type: isGeneratorMethod ? "generator" : null });
                            } else {
                                advance(":");
                                expression(10);
                            }
                        }

                        countMember(i);

                        if (state.tokens.next.id === ",") {
                            comma({ allowTrailing: true, property: true });
                            if (state.tokens.next.id === ",") {
                                warning("W070", state.tokens.curr);
                            } else if (state.tokens.next.id === "}" && !state.inES5()) {
                                warning("W070", state.tokens.curr);
                            }
                        } else {
                            break;
                        }
                    }
                    if (b) {
                        indent -= state.option.indent;
                    }
                    advance("}", this);

                    checkProperties(props);

                    return this;
                };
                x.fud = function() {
                    error("E036", state.tokens.curr);
                };
            }(delim("{")));

            function destructuringPattern(options) {
                var isAssignment = options && options.assignment;

                if (!state.inES6()) {
                    warning("W104", state.tokens.curr,
                        isAssignment ? "destructuring assignment" : "destructuring binding", "6");
                }

                return destructuringPatternRecursive(options);
            }

            function destructuringPatternRecursive(options) {
                var ids;
                var identifiers = [];
                var openingParsed = options && options.openingParsed;
                var isAssignment = options && options.assignment;
                var recursiveOptions = isAssignment ? { assignment: isAssignment } : null;
                var firstToken = openingParsed ? state.tokens.curr : state.tokens.next;

                var nextInnerDE = function() {
                    var ident;
                    if (checkPunctuators(state.tokens.next, ["[", "{"])) {
                        ids = destructuringPatternRecursive(recursiveOptions);
                        for (var id in ids) {
                            id = ids[id];
                            identifiers.push({ id: id.id, token: id.token });
                        }
                    } else if (checkPunctuator(state.tokens.next, ",")) {
                        identifiers.push({ id: null, token: state.tokens.curr });
                    } else if (checkPunctuator(state.tokens.next, "(")) {
                        advance("(");
                        nextInnerDE();
                        advance(")");
                    } else {
                        var is_rest = checkPunctuator(state.tokens.next, "...");

                        if (isAssignment) {
                            var identifierToken = is_rest ? peek(0) : state.tokens.next;
                            if (!identifierToken.identifier) {
                                warning("E030", identifierToken, identifierToken.value);
                            }
                            var assignTarget = expression(155);
                            if (assignTarget) {
                                checkLeftSideAssign(assignTarget);
                                if (assignTarget.identifier) {
                                    ident = assignTarget.value;
                                }
                            }
                        } else {
                            ident = identifier();
                        }
                        if (ident) {
                            identifiers.push({ id: ident, token: state.tokens.curr });
                        }
                        return is_rest;
                    }
                    return false;
                };
                var assignmentProperty = function() {
                    var id;
                    if (checkPunctuator(state.tokens.next, "[")) {
                        advance("[");
                        expression(10);
                        advance("]");
                        advance(":");
                        nextInnerDE();
                    } else if (state.tokens.next.id === "(string)" ||
                        state.tokens.next.id === "(number)") {
                        advance();
                        advance(":");
                        nextInnerDE();
                    } else {
                        id = identifier();
                        if (checkPunctuator(state.tokens.next, ":")) {
                            advance(":");
                            nextInnerDE();
                        } else if (id) {
                            if (isAssignment) {
                                checkLeftSideAssign(state.tokens.curr);
                            }
                            identifiers.push({ id: id, token: state.tokens.curr });
                        }
                    }
                };
                if (checkPunctuator(firstToken, "[")) {
                    if (!openingParsed) {
                        advance("[");
                    }
                    if (checkPunctuator(state.tokens.next, "]")) {
                        warning("W137", state.tokens.curr);
                    }
                    var element_after_rest = false;
                    while (!checkPunctuator(state.tokens.next, "]")) {
                        if (nextInnerDE() && !element_after_rest &&
                            checkPunctuator(state.tokens.next, ",")) {
                            warning("W130", state.tokens.next);
                            element_after_rest = true;
                        }
                        if (checkPunctuator(state.tokens.next, "=")) {
                            if (checkPunctuator(state.tokens.prev, "...")) {
                                advance("]");
                            } else {
                                advance("=");
                            }
                            if (state.tokens.next.id === "undefined") {
                                warning("W080", state.tokens.prev, state.tokens.prev.value);
                            }
                            expression(10);
                        }
                        if (!checkPunctuator(state.tokens.next, "]")) {
                            advance(",");
                        }
                    }
                    advance("]");
                } else if (checkPunctuator(firstToken, "{")) {

                    if (!openingParsed) {
                        advance("{");
                    }
                    if (checkPunctuator(state.tokens.next, "}")) {
                        warning("W137", state.tokens.curr);
                    }
                    while (!checkPunctuator(state.tokens.next, "}")) {
                        assignmentProperty();
                        if (checkPunctuator(state.tokens.next, "=")) {
                            advance("=");
                            if (state.tokens.next.id === "undefined") {
                                warning("W080", state.tokens.prev, state.tokens.prev.value);
                            }
                            expression(10);
                        }
                        if (!checkPunctuator(state.tokens.next, "}")) {
                            advance(",");
                            if (checkPunctuator(state.tokens.next, "}")) {
                                break;
                            }
                        }
                    }
                    advance("}");
                }
                return identifiers;
            }

            function destructuringPatternMatch(tokens, value) {
                var first = value.first;

                if (!first)
                    return;

                _.zip(tokens, Array.isArray(first) ? first : [ first ]).forEach(function(val) {
                    var token = val[0];
                    var value = val[1];

                    if (token && value)
                        token.first = value;
                    else if (token && token.first && !value)
                        warning("W080", token.first, token.first.value);
                });
            }

            function blockVariableStatement(type, statement, context) {

                var prefix = context && context.prefix;
                var inexport = context && context.inexport;
                var isLet = type === "let";
                var isConst = type === "const";
                var tokens, lone, value, letblock;

                if (!state.inES6()) {
                    warning("W104", state.tokens.curr, type, "6");
                }

                if (isLet && state.tokens.next.value === "(") {
                    if (!state.inMoz()) {
                        warning("W118", state.tokens.next, "let block");
                    }
                    advance("(");
                    state.funct["(scope)"].stack();
                    letblock = true;
                } else if (state.funct["(noblockscopedvar)"]) {
                    error("E048", state.tokens.curr, isConst ? "Const" : "Let");
                }

                statement.first = [];
                for (;;) {
                    var names = [];
                    if (_.contains(["{", "["], state.tokens.next.value)) {
                        tokens = destructuringPattern();
                        lone = false;
                    } else {
                        tokens = [ { id: identifier(), token: state.tokens.curr } ];
                        lone = true;
                    }

                    if (!prefix && isConst && state.tokens.next.id !== "=") {
                        warning("E012", state.tokens.curr, state.tokens.curr.value);
                    }

                    for (var t in tokens) {
                        if (tokens.hasOwnProperty(t)) {
                            t = tokens[t];
                            if (state.funct["(scope)"].block.isGlobal()) {
                                if (predefined[t.id] === false) {
                                    warning("W079", t.token, t.id);
                                }
                            }
                            if (t.id && !state.funct["(noblockscopedvar)"]) {
                                state.funct["(scope)"].addlabel(t.id, {
                                    type: type,
                                    token: t.token });
                                names.push(t.token);

                                if (lone && inexport) {
                                    state.funct["(scope)"].setExported(t.token.value, t.token);
                                }
                            }
                        }
                    }

                    if (state.tokens.next.id === "=") {
                        advance("=");
                        if (!prefix && state.tokens.next.id === "undefined") {
                            warning("W080", state.tokens.prev, state.tokens.prev.value);
                        }
                        if (!prefix && peek(0).id === "=" && state.tokens.next.identifier) {
                            warning("W120", state.tokens.next, state.tokens.next.value);
                        }
                        value = expression(prefix ? 120 : 10);
                        if (lone) {
                            tokens[0].first = value;
                        } else {
                            destructuringPatternMatch(names, value);
                        }
                    }

                    statement.first = statement.first.concat(names);

                    if (state.tokens.next.id !== ",") {
                        break;
                    }
                    comma();
                }
                if (letblock) {
                    advance(")");
                    block(true, true);
                    statement.block = true;
                    state.funct["(scope)"].unstack();
                }

                return statement;
            }

            var conststatement = stmt("const", function(context) {
                return blockVariableStatement("const", this, context);
            });
            conststatement.exps = true;

            var letstatement = stmt("let", function(context) {
                return blockVariableStatement("let", this, context);
            });
            letstatement.exps = true;

            var varstatement = stmt("var", function(context) {
                var prefix = context && context.prefix;
                var inexport = context && context.inexport;
                var tokens, lone, value;
                var implied = context && context.implied;
                var report = !(context && context.ignore);

                this.first = [];
                for (;;) {
                    var names = [];
                    if (_.contains(["{", "["], state.tokens.next.value)) {
                        tokens = destructuringPattern();
                        lone = false;
                    } else {
                        tokens = [ { id: identifier(), token: state.tokens.curr } ];
                        lone = true;
                    }

                    if (!(prefix && implied) && report && state.option.varstmt) {
                        warning("W132", this);
                    }

                    this.first = this.first.concat(names);

                    for (var t in tokens) {
                        if (tokens.hasOwnProperty(t)) {
                            t = tokens[t];
                            if (!implied && state.funct["(global)"]) {
                                if (predefined[t.id] === false) {
                                    warning("W079", t.token, t.id);
                                } else if (state.option.futurehostile === false) {
                                    if ((!state.inES5() && vars.ecmaIdentifiers[5][t.id] === false) ||
                                        (!state.inES6() && vars.ecmaIdentifiers[6][t.id] === false)) {
                                        warning("W129", t.token, t.id);
                                    }
                                }
                            }
                            if (t.id) {
                                if (implied === "for") {

                                    if (!state.funct["(scope)"].has(t.id)) {
                                        if (report) warning("W088", t.token, t.id);
                                    }
                                    state.funct["(scope)"].block.use(t.id, t.token);
                                } else {
                                    state.funct["(scope)"].addlabel(t.id, {
                                        type: "var",
                                        token: t.token });

                                    if (lone && inexport) {
                                        state.funct["(scope)"].setExported(t.id, t.token);
                                    }
                                }
                                names.push(t.token);
                            }
                        }
                    }

                    if (state.tokens.next.id === "=") {
                        state.nameStack.set(state.tokens.curr);

                        advance("=");
                        if (!prefix && report && !state.funct["(loopage)"] &&
                            state.tokens.next.id === "undefined") {
                            warning("W080", state.tokens.prev, state.tokens.prev.value);
                        }
                        if (peek(0).id === "=" && state.tokens.next.identifier) {
                            if (!prefix && report &&
                                !state.funct["(params)"] ||
                                state.funct["(params)"].indexOf(state.tokens.next.value) === -1) {
                                warning("W120", state.tokens.next, state.tokens.next.value);
                            }
                        }
                        value = expression(prefix ? 120 : 10);
                        if (lone) {
                            tokens[0].first = value;
                        } else {
                            destructuringPatternMatch(names, value);
                        }
                    }

                    if (state.tokens.next.id !== ",") {
                        break;
                    }
                    comma();
                }

                return this;
            });
            varstatement.exps = true;

            blockstmt("class", function() {
                return classdef.call(this, true);
            });

            function classdef(isStatement) {
                if (!state.inES6()) {
                    warning("W104", state.tokens.curr, "class", "6");
                }
                if (isStatement) {
                    this.name = identifier();

                    state.funct["(scope)"].addlabel(this.name, {
                        type: "class",
                        token: state.tokens.curr });
                } else if (state.tokens.next.identifier && state.tokens.next.value !== "extends") {
                    this.name = identifier();
                    this.namedExpr = true;
                } else {
                    this.name = state.nameStack.infer();
                }
                classtail(this);
                return this;
            }

            function classtail(c) {
                var wasInClassBody = state.inClassBody;
                if (state.tokens.next.value === "extends") {
                    advance("extends");
                    c.heritage = expression(10);
                }

                state.inClassBody = true;
                advance("{");
                c.body = classbody(c);
                advance("}");
                state.inClassBody = wasInClassBody;
            }

            function classbody(c) {
                var name;
                var isStatic;
                var isGenerator;
                var getset;
                var props = Object.create(null);
                var staticProps = Object.create(null);
                var computed;
                for (var i = 0; state.tokens.next.id !== "}"; ++i) {
                    name = state.tokens.next;
                    isStatic = false;
                    isGenerator = false;
                    getset = null;
                    if (name.id === ";") {
                        warning("W032");
                        advance(";");
                        continue;
                    }

                    if (name.id === "*") {
                        isGenerator = true;
                        advance("*");
                        name = state.tokens.next;
                    }
                    if (name.id === "[") {
                        name = computedPropertyName();
                        computed = true;
                    } else if (isPropertyName(name)) {
                        advance();
                        computed = false;
                        if (name.identifier && name.value === "static") {
                            if (checkPunctuator(state.tokens.next, "*")) {
                                isGenerator = true;
                                advance("*");
                            }
                            if (isPropertyName(state.tokens.next) || state.tokens.next.id === "[") {
                                computed = state.tokens.next.id === "[";
                                isStatic = true;
                                name = state.tokens.next;
                                if (state.tokens.next.id === "[") {
                                    name = computedPropertyName();
                                } else advance();
                            }
                        }

                        if (name.identifier && (name.value === "get" || name.value === "set")) {
                            if (isPropertyName(state.tokens.next) || state.tokens.next.id === "[") {
                                computed = state.tokens.next.id === "[";
                                getset = name;
                                name = state.tokens.next;
                                if (state.tokens.next.id === "[") {
                                    name = computedPropertyName();
                                } else advance();
                            }
                        }
                    } else {
                        warning("W052", state.tokens.next, state.tokens.next.value || state.tokens.next.type);
                        advance();
                        continue;
                    }

                    if (!checkPunctuator(state.tokens.next, "(")) {
                        error("E054", state.tokens.next, state.tokens.next.value);
                        while (state.tokens.next.id !== "}" &&
                        !checkPunctuator(state.tokens.next, "(")) {
                            advance();
                        }
                        if (state.tokens.next.value !== "(") {
                            doFunction({ statement: c });
                        }
                    }

                    if (!computed) {
                        if (getset) {
                            saveAccessor(
                                getset.value, isStatic ? staticProps : props, name.value, name, true, isStatic);
                        } else {
                            if (name.value === "constructor") {
                                state.nameStack.set(c);
                            } else {
                                state.nameStack.set(name);
                            }
                            saveProperty(isStatic ? staticProps : props, name.value, name, true, isStatic);
                        }
                    }

                    if (getset && name.value === "constructor") {
                        var propDesc = getset.value === "get" ? "class getter method" : "class setter method";
                        error("E049", name, propDesc, "constructor");
                    } else if (name.value === "prototype") {
                        error("E049", name, "class method", "prototype");
                    }

                    propertyName(name);

                    doFunction({
                        statement: c,
                        type: isGenerator ? "generator" : null,
                        classExprBinding: c.namedExpr ? c.name : null
                    });
                }

                checkProperties(props);
            }

            blockstmt("function", function(context) {
                var inexport = context && context.inexport;
                var generator = false;
                if (state.tokens.next.value === "*") {
                    advance("*");
                    if (state.inES6({ strict: true })) {
                        generator = true;
                    } else {
                        warning("W119", state.tokens.curr, "function*", "6");
                    }
                }
                if (inblock) {
                    warning("W082", state.tokens.curr);
                }
                var i = optionalidentifier();

                state.funct["(scope)"].addlabel(i, {
                    type: "function",
                    token: state.tokens.curr });

                if (i === undefined) {
                    warning("W025");
                } else if (inexport) {
                    state.funct["(scope)"].setExported(i, state.tokens.prev);
                }

                doFunction({
                    name: i,
                    statement: this,
                    type: generator ? "generator" : null,
                    ignoreLoopFunc: inblock // a declaration may already have warned
                });
                if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) {
                    error("E039");
                }
                return this;
            });

            prefix("function", function() {
                var generator = false;

                if (state.tokens.next.value === "*") {
                    if (!state.inES6()) {
                        warning("W119", state.tokens.curr, "function*", "6");
                    }
                    advance("*");
                    generator = true;
                }

                var i = optionalidentifier();
                doFunction({ name: i, type: generator ? "generator" : null });
                return this;
            });

            blockstmt("if", function() {
                var t = state.tokens.next;
                increaseComplexityCount();
                state.condition = true;
                advance("(");
                var expr = expression(0);
                checkCondAssignment(expr);
                var forinifcheck = null;
                if (state.option.forin && state.forinifcheckneeded) {
                    state.forinifcheckneeded = false; // We only need to analyze the first if inside the loop
                    forinifcheck = state.forinifchecks[state.forinifchecks.length - 1];
                    if (expr.type === "(punctuator)" && expr.value === "!") {
                        forinifcheck.type = "(negative)";
                    } else {
                        forinifcheck.type = "(positive)";
                    }
                }

                advance(")", t);
                state.condition = false;
                var s = block(true, true);
                if (forinifcheck && forinifcheck.type === "(negative)") {
                    if (s && s[0] && s[0].type === "(identifier)" && s[0].value === "continue") {
                        forinifcheck.type = "(negative-with-continue)";
                    }
                }

                if (state.tokens.next.id === "else") {
                    advance("else");
                    if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") {
                        statement();
                    } else {
                        block(true, true);
                    }
                }
                return this;
            });

            blockstmt("try", function() {
                var b;

                function doCatch() {
                    advance("catch");
                    advance("(");

                    state.funct["(scope)"].stack("catchparams");

                    if (checkPunctuators(state.tokens.next, ["[", "{"])) {
                        var tokens = destructuringPattern();
                        _.each(tokens, function(token) {
                            if (token.id) {
                                state.funct["(scope)"].addParam(token.id, token, "exception");
                            }
                        });
                    } else if (state.tokens.next.type !== "(identifier)") {
                        warning("E030", state.tokens.next, state.tokens.next.value);
                    } else {
                        state.funct["(scope)"].addParam(identifier(), state.tokens.curr, "exception");
                    }

                    if (state.tokens.next.value === "if") {
                        if (!state.inMoz()) {
                            warning("W118", state.tokens.curr, "catch filter");
                        }
                        advance("if");
                        expression(0);
                    }

                    advance(")");

                    block(false);

                    state.funct["(scope)"].unstack();
                }

                block(true);

                while (state.tokens.next.id === "catch") {
                    increaseComplexityCount();
                    if (b && (!state.inMoz())) {
                        warning("W118", state.tokens.next, "multiple catch blocks");
                    }
                    doCatch();
                    b = true;
                }

                if (state.tokens.next.id === "finally") {
                    advance("finally");
                    block(true);
                    return;
                }

                if (!b) {
                    error("E021", state.tokens.next, "catch", state.tokens.next.value);
                }

                return this;
            });

            blockstmt("while", function() {
                var t = state.tokens.next;
                state.funct["(breakage)"] += 1;
                state.funct["(loopage)"] += 1;
                increaseComplexityCount();
                advance("(");
                checkCondAssignment(expression(0));
                advance(")", t);
                block(true, true);
                state.funct["(breakage)"] -= 1;
                state.funct["(loopage)"] -= 1;
                return this;
            }).labelled = true;

            blockstmt("with", function() {
                var t = state.tokens.next;
                if (state.isStrict()) {
                    error("E010", state.tokens.curr);
                } else if (!state.option.withstmt) {
                    warning("W085", state.tokens.curr);
                }

                advance("(");
                expression(0);
                advance(")", t);
                block(true, true);

                return this;
            });

            blockstmt("switch", function() {
                var t = state.tokens.next;
                var g = false;
                var noindent = false;

                state.funct["(breakage)"] += 1;
                advance("(");
                checkCondAssignment(expression(0));
                advance(")", t);
                t = state.tokens.next;
                advance("{");

                if (state.tokens.next.from === indent)
                    noindent = true;

                if (!noindent)
                    indent += state.option.indent;

                this.cases = [];

                for (;;) {
                    switch (state.tokens.next.id) {
                        case "case":
                            switch (state.funct["(verb)"]) {
                                case "yield":
                                case "break":
                                case "case":
                                case "continue":
                                case "return":
                                case "switch":
                                case "throw":
                                    break;
                                default:
                                    if (!state.tokens.curr.caseFallsThrough) {
                                        warning("W086", state.tokens.curr, "case");
                                    }
                            }

                            advance("case");
                            this.cases.push(expression(0));
                            increaseComplexityCount();
                            g = true;
                            advance(":");
                            state.funct["(verb)"] = "case";
                            break;
                        case "default":
                            switch (state.funct["(verb)"]) {
                                case "yield":
                                case "break":
                                case "continue":
                                case "return":
                                case "throw":
                                    break;
                                default:
                                    if (this.cases.length) {
                                        if (!state.tokens.curr.caseFallsThrough) {
                                            warning("W086", state.tokens.curr, "default");
                                        }
                                    }
                            }

                            advance("default");
                            g = true;
                            advance(":");
                            break;
                        case "}":
                            if (!noindent)
                                indent -= state.option.indent;

                            advance("}", t);
                            state.funct["(breakage)"] -= 1;
                            state.funct["(verb)"] = undefined;
                            return;
                        case "(end)":
                            error("E023", state.tokens.next, "}");
                            return;
                        default:
                            indent += state.option.indent;
                            if (g) {
                                switch (state.tokens.curr.id) {
                                    case ",":
                                        error("E040");
                                        return;
                                    case ":":
                                        g = false;
                                        statements();
                                        break;
                                    default:
                                        error("E025", state.tokens.curr);
                                        return;
                                }
                            } else {
                                if (state.tokens.curr.id === ":") {
                                    advance(":");
                                    error("E024", state.tokens.curr, ":");
                                    statements();
                                } else {
                                    error("E021", state.tokens.next, "case", state.tokens.next.value);
                                    return;
                                }
                            }
                            indent -= state.option.indent;
                    }
                }
                return this;
            }).labelled = true;

            stmt("debugger", function() {
                if (!state.option.debug) {
                    warning("W087", this);
                }
                return this;
            }).exps = true;

            (function() {
                var x = stmt("do", function() {
                    state.funct["(breakage)"] += 1;
                    state.funct["(loopage)"] += 1;
                    increaseComplexityCount();

                    this.first = block(true, true);
                    advance("while");
                    var t = state.tokens.next;
                    advance("(");
                    checkCondAssignment(expression(0));
                    advance(")", t);
                    state.funct["(breakage)"] -= 1;
                    state.funct["(loopage)"] -= 1;
                    return this;
                });
                x.labelled = true;
                x.exps = true;
            }());

            blockstmt("for", function() {
                var s, t = state.tokens.next;
                var letscope = false;
                var foreachtok = null;

                if (t.value === "each") {
                    foreachtok = t;
                    advance("each");
                    if (!state.inMoz()) {
                        warning("W118", state.tokens.curr, "for each");
                    }
                }

                increaseComplexityCount();
                advance("(");
                var nextop; // contains the token of the "in" or "of" operator
                var i = 0;
                var inof = ["in", "of"];
                var level = 0; // BindingPattern "level" --- level 0 === no BindingPattern
                var comma; // First comma punctuator at level 0
                var initializer; // First initializer at level 0
                if (checkPunctuators(state.tokens.next, ["{", "["])) ++level;
                do {
                    nextop = peek(i);
                    ++i;
                    if (checkPunctuators(nextop, ["{", "["])) ++level;
                    else if (checkPunctuators(nextop, ["}", "]"])) --level;
                    if (level < 0) break;
                    if (level === 0) {
                        if (!comma && checkPunctuator(nextop, ",")) comma = nextop;
                        else if (!initializer && checkPunctuator(nextop, "=")) initializer = nextop;
                    }
                } while (level > 0 || !_.contains(inof, nextop.value) && nextop.value !== ";" &&
                nextop.type !== "(end)"); // Is this a JSCS bug? This looks really weird.
                if (_.contains(inof, nextop.value)) {
                    if (!state.inES6() && nextop.value === "of") {
                        warning("W104", nextop, "for of", "6");
                    }

                    var ok = !(initializer || comma);
                    if (initializer) {
                        error("W133", comma, nextop.value, "initializer is forbidden");
                    }

                    if (comma) {
                        error("W133", comma, nextop.value, "more than one ForBinding");
                    }

                    if (state.tokens.next.id === "var") {
                        advance("var");
                        state.tokens.curr.fud({ prefix: true });
                    } else if (state.tokens.next.id === "let" || state.tokens.next.id === "const") {
                        advance(state.tokens.next.id);
                        letscope = true;
                        state.funct["(scope)"].stack();
                        state.tokens.curr.fud({ prefix: true });
                    } else {
                        Object.create(varstatement).fud({ prefix: true, implied: "for", ignore: !ok });
                    }
                    advance(nextop.value);
                    expression(20);
                    advance(")", t);

                    if (nextop.value === "in" && state.option.forin) {
                        state.forinifcheckneeded = true;

                        if (state.forinifchecks === undefined) {
                            state.forinifchecks = [];
                        }
                        state.forinifchecks.push({
                            type: "(none)"
                        });
                    }

                    state.funct["(breakage)"] += 1;
                    state.funct["(loopage)"] += 1;

                    s = block(true, true);

                    if (nextop.value === "in" && state.option.forin) {
                        if (state.forinifchecks && state.forinifchecks.length > 0) {
                            var check = state.forinifchecks.pop();

                            if (// No if statement or not the first statement in loop body
                            s && s.length > 0 && (typeof s[0] !== "object" || s[0].value !== "if") ||
                            check.type === "(positive)" && s.length > 1 ||
                            check.type === "(negative)") {
                                warning("W089", this);
                            }
                        }
                        state.forinifcheckneeded = false;
                    }

                    state.funct["(breakage)"] -= 1;
                    state.funct["(loopage)"] -= 1;
                } else {
                    if (foreachtok) {
                        error("E045", foreachtok);
                    }
                    if (state.tokens.next.id !== ";") {
                        if (state.tokens.next.id === "var") {
                            advance("var");
                            state.tokens.curr.fud();
                        } else if (state.tokens.next.id === "let") {
                            advance("let");
                            letscope = true;
                            state.funct["(scope)"].stack();
                            state.tokens.curr.fud();
                        } else {
                            for (;;) {
                                expression(0, "for");
                                if (state.tokens.next.id !== ",") {
                                    break;
                                }
                                comma();
                            }
                        }
                    }
                    nolinebreak(state.tokens.curr);
                    advance(";");
                    state.funct["(loopage)"] += 1;
                    if (state.tokens.next.id !== ";") {
                        checkCondAssignment(expression(0));
                    }
                    nolinebreak(state.tokens.curr);
                    advance(";");
                    if (state.tokens.next.id === ";") {
                        error("E021", state.tokens.next, ")", ";");
                    }
                    if (state.tokens.next.id !== ")") {
                        for (;;) {
                            expression(0, "for");
                            if (state.tokens.next.id !== ",") {
                                break;
                            }
                            comma();
                        }
                    }
                    advance(")", t);
                    state.funct["(breakage)"] += 1;
                    block(true, true);
                    state.funct["(breakage)"] -= 1;
                    state.funct["(loopage)"] -= 1;

                }
                if (letscope) {
                    state.funct["(scope)"].unstack();
                }
                return this;
            }).labelled = true;


            stmt("break", function() {
                var v = state.tokens.next.value;

                if (!state.option.asi)
                    nolinebreak(this);

                if (state.tokens.next.id !== ";" && !state.tokens.next.reach &&
                    state.tokens.curr.line === startLine(state.tokens.next)) {
                    if (!state.funct["(scope)"].funct.hasBreakLabel(v)) {
                        warning("W090", state.tokens.next, v);
                    }
                    this.first = state.tokens.next;
                    advance();
                } else {
                    if (state.funct["(breakage)"] === 0)
                        warning("W052", state.tokens.next, this.value);
                }

                reachable(this);

                return this;
            }).exps = true;


            stmt("continue", function() {
                var v = state.tokens.next.value;

                if (state.funct["(breakage)"] === 0)
                    warning("W052", state.tokens.next, this.value);
                if (!state.funct["(loopage)"])
                    warning("W052", state.tokens.next, this.value);

                if (!state.option.asi)
                    nolinebreak(this);

                if (state.tokens.next.id !== ";" && !state.tokens.next.reach) {
                    if (state.tokens.curr.line === startLine(state.tokens.next)) {
                        if (!state.funct["(scope)"].funct.hasBreakLabel(v)) {
                            warning("W090", state.tokens.next, v);
                        }
                        this.first = state.tokens.next;
                        advance();
                    }
                }

                reachable(this);

                return this;
            }).exps = true;


            stmt("return", function() {
                if (this.line === startLine(state.tokens.next)) {
                    if (state.tokens.next.id !== ";" && !state.tokens.next.reach) {
                        this.first = expression(0);

                        if (this.first &&
                            this.first.type === "(punctuator)" && this.first.value === "=" &&
                            !this.first.paren && !state.option.boss) {
                            warningAt("W093", this.first.line, this.first.character);
                        }
                    }
                } else {
                    if (state.tokens.next.type === "(punctuator)" &&
                        ["[", "{", "+", "-"].indexOf(state.tokens.next.value) > -1) {
                        nolinebreak(this); // always warn (Line breaking error)
                    }
                }

                reachable(this);

                return this;
            }).exps = true;

            (function(x) {
                x.exps = true;
                x.lbp = 25;
            }(prefix("yield", function() {
                var prev = state.tokens.prev;
                if (state.inES6(true) && !state.funct["(generator)"]) {
                    if (!("(catch)" === state.funct["(name)"] && state.funct["(context)"]["(generator)"])) {
                        error("E046", state.tokens.curr, "yield");
                    }
                } else if (!state.inES6()) {
                    warning("W104", state.tokens.curr, "yield", "6");
                }
                state.funct["(generator)"] = "yielded";
                var delegatingYield = false;

                if (state.tokens.next.value === "*") {
                    delegatingYield = true;
                    advance("*");
                }

                if (this.line === startLine(state.tokens.next) || !state.inMoz()) {
                    if (delegatingYield ||
                        (state.tokens.next.id !== ";" && !state.option.asi &&
                        !state.tokens.next.reach && state.tokens.next.nud)) {

                        nobreaknonadjacent(state.tokens.curr, state.tokens.next);
                        this.first = expression(10);

                        if (this.first.type === "(punctuator)" && this.first.value === "=" &&
                            !this.first.paren && !state.option.boss) {
                            warningAt("W093", this.first.line, this.first.character);
                        }
                    }

                    if (state.inMoz() && state.tokens.next.id !== ")" &&
                        (prev.lbp > 30 || (!prev.assign && !isEndOfExpr()) || prev.id === "yield")) {
                        error("E050", this);
                    }
                } else if (!state.option.asi) {
                    nolinebreak(this); // always warn (Line breaking error)
                }
                return this;
            })));


            stmt("throw", function() {
                nolinebreak(this);
                this.first = expression(20);

                reachable(this);

                return this;
            }).exps = true;

            stmt("import", function() {
                if (!state.inES6()) {
                    warning("W119", state.tokens.curr, "import", "6");
                }

                if (state.tokens.next.type === "(string)") {
                    advance("(string)");
                    return this;
                }

                if (state.tokens.next.identifier) {
                    this.name = identifier();
                    state.funct["(scope)"].addlabel(this.name, {
                        type: "const",
                        token: state.tokens.curr });

                    if (state.tokens.next.value === ",") {
                        advance(",");
                    } else {
                        advance("from");
                        advance("(string)");
                        return this;
                    }
                }

                if (state.tokens.next.id === "*") {
                    advance("*");
                    advance("as");
                    if (state.tokens.next.identifier) {
                        this.name = identifier();
                        state.funct["(scope)"].addlabel(this.name, {
                            type: "const",
                            token: state.tokens.curr });
                    }
                } else {
                    advance("{");
                    for (;;) {
                        if (state.tokens.next.value === "}") {
                            advance("}");
                            break;
                        }
                        var importName;
                        if (state.tokens.next.type === "default") {
                            importName = "default";
                            advance("default");
                        } else {
                            importName = identifier();
                        }
                        if (state.tokens.next.value === "as") {
                            advance("as");
                            importName = identifier();
                        }
                        state.funct["(scope)"].addlabel(importName, {
                            type: "const",
                            token: state.tokens.curr });

                        if (state.tokens.next.value === ",") {
                            advance(",");
                        } else if (state.tokens.next.value === "}") {
                            advance("}");
                            break;
                        } else {
                            error("E024", state.tokens.next, state.tokens.next.value);
                            break;
                        }
                    }
                }
                advance("from");
                advance("(string)");
                return this;
            }).exps = true;

            stmt("export", function() {
                var ok = true;
                var token;
                var identifier;

                if (!state.inES6()) {
                    warning("W119", state.tokens.curr, "export", "6");
                    ok = false;
                }

                if (!state.funct["(scope)"].block.isGlobal()) {
                    error("E053", state.tokens.curr);
                    ok = false;
                }

                if (state.tokens.next.value === "*") {
                    advance("*");
                    advance("from");
                    advance("(string)");
                    return this;
                }

                if (state.tokens.next.type === "default") {
                    state.nameStack.set(state.tokens.next);
                    advance("default");
                    var exportType = state.tokens.next.id;
                    if (exportType === "function" || exportType === "class") {
                        this.block = true;
                    }

                    token = peek();

                    expression(10);

                    identifier = token.value;

                    if (this.block) {
                        state.funct["(scope)"].addlabel(identifier, {
                            type: exportType,
                            token: token });

                        state.funct["(scope)"].setExported(identifier, token);
                    }

                    return this;
                }

                if (state.tokens.next.value === "{") {
                    advance("{");
                    var exportedTokens = [];
                    for (;;) {
                        if (!state.tokens.next.identifier) {
                            error("E030", state.tokens.next, state.tokens.next.value);
                        }
                        advance();

                        exportedTokens.push(state.tokens.curr);

                        if (state.tokens.next.value === "as") {
                            advance("as");
                            if (!state.tokens.next.identifier) {
                                error("E030", state.tokens.next, state.tokens.next.value);
                            }
                            advance();
                        }

                        if (state.tokens.next.value === ",") {
                            advance(",");
                        } else if (state.tokens.next.value === "}") {
                            advance("}");
                            break;
                        } else {
                            error("E024", state.tokens.next, state.tokens.next.value);
                            break;
                        }
                    }
                    if (state.tokens.next.value === "from") {
                        advance("from");
                        advance("(string)");
                    } else if (ok) {
                        exportedTokens.forEach(function(token) {
                            state.funct["(scope)"].setExported(token.value, token);
                        });
                    }
                    return this;
                }

                if (state.tokens.next.id === "var") {
                    advance("var");
                    state.tokens.curr.fud({ inexport:true });
                } else if (state.tokens.next.id === "let") {
                    advance("let");
                    state.tokens.curr.fud({ inexport:true });
                } else if (state.tokens.next.id === "const") {
                    advance("const");
                    state.tokens.curr.fud({ inexport:true });
                } else if (state.tokens.next.id === "function") {
                    this.block = true;
                    advance("function");
                    state.syntax["function"].fud({ inexport:true });
                } else if (state.tokens.next.id === "class") {
                    this.block = true;
                    advance("class");
                    var classNameToken = state.tokens.next;
                    state.syntax["class"].fud();
                    state.funct["(scope)"].setExported(classNameToken.value, classNameToken);
                } else {
                    error("E024", state.tokens.next, state.tokens.next.value);
                }

                return this;
            }).exps = true;

            FutureReservedWord("abstract");
            FutureReservedWord("boolean");
            FutureReservedWord("byte");
            FutureReservedWord("char");
            FutureReservedWord("class", { es5: true, nud: classdef });
            FutureReservedWord("double");
            FutureReservedWord("enum", { es5: true });
            FutureReservedWord("export", { es5: true });
            FutureReservedWord("extends", { es5: true });
            FutureReservedWord("final");
            FutureReservedWord("float");
            FutureReservedWord("goto");
            FutureReservedWord("implements", { es5: true, strictOnly: true });
            FutureReservedWord("import", { es5: true });
            FutureReservedWord("int");
            FutureReservedWord("interface", { es5: true, strictOnly: true });
            FutureReservedWord("long");
            FutureReservedWord("native");
            FutureReservedWord("package", { es5: true, strictOnly: true });
            FutureReservedWord("private", { es5: true, strictOnly: true });
            FutureReservedWord("protected", { es5: true, strictOnly: true });
            FutureReservedWord("public", { es5: true, strictOnly: true });
            FutureReservedWord("short");
            FutureReservedWord("static", { es5: true, strictOnly: true });
            FutureReservedWord("super", { es5: true });
            FutureReservedWord("synchronized");
            FutureReservedWord("transient");
            FutureReservedWord("volatile");

            var lookupBlockType = function() {
                var pn, pn1, prev;
                var i = -1;
                var bracketStack = 0;
                var ret = {};
                if (checkPunctuators(state.tokens.curr, ["[", "{"])) {
                    bracketStack += 1;
                }
                do {
                    prev = i === -1 ? state.tokens.curr : pn;
                    pn = i === -1 ? state.tokens.next : peek(i);
                    pn1 = peek(i + 1);
                    i = i + 1;
                    if (checkPunctuators(pn, ["[", "{"])) {
                        bracketStack += 1;
                    } else if (checkPunctuators(pn, ["]", "}"])) {
                        bracketStack -= 1;
                    }
                    if (bracketStack === 1 && pn.identifier && pn.value === "for" &&
                        !checkPunctuator(prev, ".")) {
                        ret.isCompArray = true;
                        ret.notJson = true;
                        break;
                    }
                    if (bracketStack === 0 && checkPunctuators(pn, ["}", "]"])) {
                        if (pn1.value === "=") {
                            ret.isDestAssign = true;
                            ret.notJson = true;
                            break;
                        } else if (pn1.value === ".") {
                            ret.notJson = true;
                            break;
                        }
                    }
                    if (checkPunctuator(pn, ";")) {
                        ret.isBlock = true;
                        ret.notJson = true;
                    }
                } while (bracketStack > 0 && pn.id !== "(end)");
                return ret;
            };

            function saveProperty(props, name, tkn, isClass, isStatic) {
                var msg = ["key", "class method", "static class method"];
                msg = msg[(isClass || false) + (isStatic || false)];
                if (tkn.identifier) {
                    name = tkn.value;
                }

                if (props[name] && name !== "__proto__") {
                    warning("W075", state.tokens.next, msg, name);
                } else {
                    props[name] = Object.create(null);
                }

                props[name].basic = true;
                props[name].basictkn = tkn;
            }
            function saveAccessor(accessorType, props, name, tkn, isClass, isStatic) {
                var flagName = accessorType === "get" ? "getterToken" : "setterToken";
                var msg = "";

                if (isClass) {
                    if (isStatic) {
                        msg += "static ";
                    }
                    msg += accessorType + "ter method";
                } else {
                    msg = "key";
                }

                state.tokens.curr.accessorType = accessorType;
                state.nameStack.set(tkn);

                if (props[name]) {
                    if ((props[name].basic || props[name][flagName]) && name !== "__proto__") {
                        warning("W075", state.tokens.next, msg, name);
                    }
                } else {
                    props[name] = Object.create(null);
                }

                props[name][flagName] = tkn;
            }

            function computedPropertyName() {
                advance("[");
                if (!state.inES6()) {
                    warning("W119", state.tokens.curr, "computed property names", "6");
                }
                var value = expression(10);
                advance("]");
                return value;
            }
            function checkPunctuators(token, values) {
                if (token.type === "(punctuator)") {
                    return _.contains(values, token.value);
                }
                return false;
            }
            function checkPunctuator(token, value) {
                return token.type === "(punctuator)" && token.value === value;
            }
            function destructuringAssignOrJsonValue() {

                var block = lookupBlockType();
                if (block.notJson) {
                    if (!state.inES6() && block.isDestAssign) {
                        warning("W104", state.tokens.curr, "destructuring assignment", "6");
                    }
                    statements();
                } else {
                    state.option.laxbreak = true;
                    state.jsonMode = true;
                    jsonValue();
                }
            }

            var arrayComprehension = function() {
                var CompArray = function() {
                    this.mode = "use";
                    this.variables = [];
                };
                var _carrays = [];
                var _current;
                function declare(v) {
                    var l = _current.variables.filter(function(elt) {
                        if (elt.value === v) {
                            elt.undef = false;
                            return v;
                        }
                    }).length;
                    return l !== 0;
                }
                function use(v) {
                    var l = _current.variables.filter(function(elt) {
                        if (elt.value === v && !elt.undef) {
                            if (elt.unused === true) {
                                elt.unused = false;
                            }
                            return v;
                        }
                    }).length;
                    return (l === 0);
                }
                return { stack: function() {
                    _current = new CompArray();
                    _carrays.push(_current);
                },
                    unstack: function() {
                        _current.variables.filter(function(v) {
                            if (v.unused)
                                warning("W098", v.token, v.raw_text || v.value);
                            if (v.undef)
                                state.funct["(scope)"].block.use(v.value, v.token);
                        });
                        _carrays.splice(-1, 1);
                        _current = _carrays[_carrays.length - 1];
                    },
                    setState: function(s) {
                        if (_.contains(["use", "define", "generate", "filter"], s))
                            _current.mode = s;
                    },
                    check: function(v) {
                        if (!_current) {
                            return;
                        }
                        if (_current && _current.mode === "use") {
                            if (use(v)) {
                                _current.variables.push({
                                    funct: state.funct,
                                    token: state.tokens.curr,
                                    value: v,
                                    undef: true,
                                    unused: false
                                });
                            }
                            return true;
                        } else if (_current && _current.mode === "define") {
                            if (!declare(v)) {
                                _current.variables.push({
                                    funct: state.funct,
                                    token: state.tokens.curr,
                                    value: v,
                                    undef: false,
                                    unused: true
                                });
                            }
                            return true;
                        } else if (_current && _current.mode === "generate") {
                            state.funct["(scope)"].block.use(v, state.tokens.curr);
                            return true;
                        } else if (_current && _current.mode === "filter") {
                            if (use(v)) {
                                state.funct["(scope)"].block.use(v, state.tokens.curr);
                            }
                            return true;
                        }
                        return false;
                    }
                };
            };

            function jsonValue() {
                function jsonObject() {
                    var o = {}, t = state.tokens.next;
                    advance("{");
                    if (state.tokens.next.id !== "}") {
                        for (;;) {
                            if (state.tokens.next.id === "(end)") {
                                error("E026", state.tokens.next, t.line);
                            } else if (state.tokens.next.id === "}") {
                                warning("W094", state.tokens.curr);
                                break;
                            } else if (state.tokens.next.id === ",") {
                                error("E028", state.tokens.next);
                            } else if (state.tokens.next.id !== "(string)") {
                                warning("W095", state.tokens.next, state.tokens.next.value);
                            }
                            if (o[state.tokens.next.value] === true) {
                                warning("W075", state.tokens.next, "key", state.tokens.next.value);
                            } else if ((state.tokens.next.value === "__proto__" &&
                                !state.option.proto) || (state.tokens.next.value === "__iterator__" &&
                                !state.option.iterator)) {
                                warning("W096", state.tokens.next, state.tokens.next.value);
                            } else {
                                o[state.tokens.next.value] = true;
                            }
                            advance();
                            advance(":");
                            jsonValue();
                            if (state.tokens.next.id !== ",") {
                                break;
                            }
                            advance(",");
                        }
                    }
                    advance("}");
                }

                function jsonArray() {
                    var t = state.tokens.next;
                    advance("[");
                    if (state.tokens.next.id !== "]") {
                        for (;;) {
                            if (state.tokens.next.id === "(end)") {
                                error("E027", state.tokens.next, t.line);
                            } else if (state.tokens.next.id === "]") {
                                warning("W094", state.tokens.curr);
                                break;
                            } else if (state.tokens.next.id === ",") {
                                error("E028", state.tokens.next);
                            }
                            jsonValue();
                            if (state.tokens.next.id !== ",") {
                                break;
                            }
                            advance(",");
                        }
                    }
                    advance("]");
                }

                switch (state.tokens.next.id) {
                    case "{":
                        jsonObject();
                        break;
                    case "[":
                        jsonArray();
                        break;
                    case "true":
                    case "false":
                    case "null":
                    case "(number)":
                    case "(string)":
                        advance();
                        break;
                    case "-":
                        advance("-");
                        advance("(number)");
                        break;
                    default:
                        error("E003", state.tokens.next);
                }
            }

            var escapeRegex = function(str) {
                return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
            };
            var itself = function(s, o, g) {
                var i, k, x, reIgnoreStr, reIgnore;
                var optionKeys;
                var newOptionObj = {};
                var newIgnoredObj = {};

                o = _.clone(o);
                state.reset();

                if (o && o.scope) {
                    JSHINT.scope = o.scope;
                } else {
                    JSHINT.errors = [];
                    JSHINT.undefs = [];
                    JSHINT.internals = [];
                    JSHINT.blacklist = {};
                    JSHINT.scope = "(main)";
                }

                predefined = Object.create(null);
                combine(predefined, vars.ecmaIdentifiers[3]);
                combine(predefined, vars.reservedVars);

                combine(predefined, g || {});

                declared = Object.create(null);
                var exported = Object.create(null); // Variables that live outside the current file

                function each(obj, cb) {
                    if (!obj)
                        return;

                    if (!Array.isArray(obj) && typeof obj === "object")
                        obj = Object.keys(obj);

                    obj.forEach(cb);
                }

                if (o) {
                    each(o.predef || null, function(item) {
                        var slice, prop;

                        if (item[0] === "-") {
                            slice = item.slice(1);
                            JSHINT.blacklist[slice] = slice;
                            delete predefined[slice];
                        } else {
                            prop = Object.getOwnPropertyDescriptor(o.predef, item);
                            predefined[item] = prop ? prop.value : false;
                        }
                    });

                    each(o.exported || null, function(item) {
                        exported[item] = true;
                    });

                    delete o.predef;
                    delete o.exported;

                    optionKeys = Object.keys(o);
                    for (x = 0; x < optionKeys.length; x++) {
                        if (/^-W\d{3}$/g.test(optionKeys[x])) {
                            newIgnoredObj[optionKeys[x].slice(1)] = true;
                        } else {
                            var optionKey = optionKeys[x];
                            newOptionObj[optionKey] = o[optionKey];
                            if ((optionKey === "esversion" && o[optionKey] === 5) ||
                                (optionKey === "es5" && o[optionKey])) {
                                warning("I003");
                            }

                            if (optionKeys[x] === "newcap" && o[optionKey] === false)
                                newOptionObj["(explicitNewcap)"] = true;
                        }
                    }
                }

                state.option = newOptionObj;
                state.ignored = newIgnoredObj;

                state.option.indent = state.option.indent || 4;
                state.option.maxerr = state.option.maxerr || 50;

                indent = 1;

                var scopeManagerInst = scopeManager(state, predefined, exported, declared);
                scopeManagerInst.on("warning", function(ev) {
                    warning.apply(null, [ ev.code, ev.token].concat(ev.data));
                });

                scopeManagerInst.on("error", function(ev) {
                    error.apply(null, [ ev.code, ev.token ].concat(ev.data));
                });

                state.funct = functor("(global)", null, {
                    "(global)"    : true,
                    "(scope)"     : scopeManagerInst,
                    "(comparray)" : arrayComprehension(),
                    "(metrics)"   : createMetrics(state.tokens.next)
                });

                functions = [state.funct];
                urls = [];
                stack = null;
                member = {};
                membersOnly = null;
                inblock = false;
                lookahead = [];

                if (!isString(s) && !Array.isArray(s)) {
                    errorAt("E004", 0);
                    return false;
                }

                api = {
                    get isJSON() {
                        return state.jsonMode;
                    },

                    getOption: function(name) {
                        return state.option[name] || null;
                    },

                    getCache: function(name) {
                        return state.cache[name];
                    },

                    setCache: function(name, value) {
                        state.cache[name] = value;
                    },

                    warn: function(code, data) {
                        warningAt.apply(null, [ code, data.line, data.char ].concat(data.data));
                    },

                    on: function(names, listener) {
                        names.split(" ").forEach(function(name) {
                            emitter.on(name, listener);
                        }.bind(this));
                    }
                };

                emitter.removeAllListeners();
                (extraModules || []).forEach(function(func) {
                    func(api);
                });

                state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"];

                if (o && o.ignoreDelimiters) {

                    if (!Array.isArray(o.ignoreDelimiters)) {
                        o.ignoreDelimiters = [o.ignoreDelimiters];
                    }

                    o.ignoreDelimiters.forEach(function(delimiterPair) {
                        if (!delimiterPair.start || !delimiterPair.end)
                            return;

                        reIgnoreStr = escapeRegex(delimiterPair.start) +
                            "[\\s\\S]*?" +
                            escapeRegex(delimiterPair.end);

                        reIgnore = new RegExp(reIgnoreStr, "ig");

                        s = s.replace(reIgnore, function(match) {
                            return match.replace(/./g, " ");
                        });
                    });
                }

                lex = new Lexer(s);

                lex.on("warning", function(ev) {
                    warningAt.apply(null, [ ev.code, ev.line, ev.character].concat(ev.data));
                });

                lex.on("error", function(ev) {
                    errorAt.apply(null, [ ev.code, ev.line, ev.character ].concat(ev.data));
                });

                lex.on("fatal", function(ev) {
                    quit("E041", ev.line, ev.from);
                });

                lex.on("Identifier", function(ev) {
                    emitter.emit("Identifier", ev);
                });

                lex.on("String", function(ev) {
                    emitter.emit("String", ev);
                });

                lex.on("Number", function(ev) {
                    emitter.emit("Number", ev);
                });

                lex.start();
                for (var name in o) {
                    if (_.has(o, name)) {
                        checkOption(name, state.tokens.curr);
                    }
                }

                assume();
                combine(predefined, g || {});
                comma.first = true;

                try {
                    advance();
                    switch (state.tokens.next.id) {
                        case "{":
                        case "[":
                            destructuringAssignOrJsonValue();
                            break;
                        default:
                            directives();

                            if (state.directive["use strict"]) {
                                if (state.option.strict !== "global") {
                                    warning("W097", state.tokens.prev);
                                }
                            }

                            statements();
                    }

                    if (state.tokens.next.id !== "(end)") {
                        quit("E041", state.tokens.curr.line);
                    }

                    state.funct["(scope)"].unstack();

                } catch (err) {
                    if (err && err.name === "JSHintError") {
                        var nt = state.tokens.next || {};
                        JSHINT.errors.push({
                            scope     : "(main)",
                            raw       : err.raw,
                            code      : err.code,
                            reason    : err.message,
                            line      : err.line || nt.line,
                            character : err.character || nt.from
                        }, null);
                    } else {
                        throw err;
                    }
                }

                if (JSHINT.scope === "(main)") {
                    o = o || {};

                    for (i = 0; i < JSHINT.internals.length; i += 1) {
                        k = JSHINT.internals[i];
                        o.scope = k.elem;
                        itself(k.value, o, g);
                    }
                }

                return JSHINT.errors.length === 0;
            };
            itself.addModule = function(func) {
                extraModules.push(func);
            };

            itself.addModule(style.register);
            itself.data = function() {
                var data = {
                    functions: [],
                    options: state.option
                };

                var fu, f, i, j, n, globals;

                if (itself.errors.length) {
                    data.errors = itself.errors;
                }

                if (state.jsonMode) {
                    data.json = true;
                }

                var impliedGlobals = state.funct["(scope)"].getImpliedGlobals();
                if (impliedGlobals.length > 0) {
                    data.implieds = impliedGlobals;
                }

                if (urls.length > 0) {
                    data.urls = urls;
                }

                globals = state.funct["(scope)"].getUsedOrDefinedGlobals();
                if (globals.length > 0) {
                    data.globals = globals;
                }

                for (i = 1; i < functions.length; i += 1) {
                    f = functions[i];
                    fu = {};

                    for (j = 0; j < functionicity.length; j += 1) {
                        fu[functionicity[j]] = [];
                    }

                    for (j = 0; j < functionicity.length; j += 1) {
                        if (fu[functionicity[j]].length === 0) {
                            delete fu[functionicity[j]];
                        }
                    }

                    fu.name = f["(name)"];
                    fu.param = f["(params)"];
                    fu.line = f["(line)"];
                    fu.character = f["(character)"];
                    fu.last = f["(last)"];
                    fu.lastcharacter = f["(lastcharacter)"];

                    fu.metrics = {
                        complexity: f["(metrics)"].ComplexityCount,
                        parameters: f["(metrics)"].arity,
                        statements: f["(metrics)"].statementCount
                    };

                    data.functions.push(fu);
                }

                var unuseds = state.funct["(scope)"].getUnuseds();
                if (unuseds.length > 0) {
                    data.unused = unuseds;
                }

                for (n in member) {
                    if (typeof member[n] === "number") {
                        data.member = member;
                        break;
                    }
                }

                return data;
            };

            itself.jshint = itself;

            return itself;
        }());
        if (typeof exports === "object" && exports) {
            exports.JSHINT = JSHINT;
        }

    },{"../lodash":"/node_modules/jshint/lodash.js","./lex.js":"/node_modules/jshint/src/lex.js","./messages.js":"/node_modules/jshint/src/messages.js","./options.js":"/node_modules/jshint/src/options.js","./reg.js":"/node_modules/jshint/src/reg.js","./scope-manager.js":"/node_modules/jshint/src/scope-manager.js","./state.js":"/node_modules/jshint/src/state.js","./style.js":"/node_modules/jshint/src/style.js","./vars.js":"/node_modules/jshint/src/vars.js","events":"/node_modules/browserify/node_modules/events/events.js"}],"/node_modules/jshint/src/lex.js":[function(_dereq_,module,exports){

        "use strict";

        var _      = _dereq_("../lodash");
        var events = _dereq_("events");
        var reg    = _dereq_("./reg.js");
        var state  = _dereq_("./state.js").state;

        var unicodeData = _dereq_("../data/ascii-identifier-data.js");
        var asciiIdentifierStartTable = unicodeData.asciiIdentifierStartTable;
        var asciiIdentifierPartTable = unicodeData.asciiIdentifierPartTable;

        var Token = {
            Identifier: 1,
            Punctuator: 2,
            NumericLiteral: 3,
            StringLiteral: 4,
            Comment: 5,
            Keyword: 6,
            NullLiteral: 7,
            BooleanLiteral: 8,
            RegExp: 9,
            TemplateHead: 10,
            TemplateMiddle: 11,
            TemplateTail: 12,
            NoSubstTemplate: 13
        };

        var Context = {
            Block: 1,
            Template: 2
        };

        function asyncTrigger() {
            var _checks = [];

            return {
                push: function(fn) {
                    _checks.push(fn);
                },

                check: function() {
                    for (var check = 0; check < _checks.length; ++check) {
                        _checks[check]();
                    }

                    _checks.splice(0, _checks.length);
                }
            };
        }
        function Lexer(source) {
            var lines = source;

            if (typeof lines === "string") {
                lines = lines
                    .replace(/\r\n/g, "\n")
                    .replace(/\r/g, "\n")
                    .split("\n");
            }

            if (lines[0] && lines[0].substr(0, 2) === "#!") {
                if (lines[0].indexOf("node") !== -1) {
                    state.option.node = true;
                }
                lines[0] = "";
            }

            this.emitter = new events.EventEmitter();
            this.source = source;
            this.setLines(lines);
            this.prereg = true;

            this.line = 0;
            this.char = 1;
            this.from = 1;
            this.input = "";
            this.inComment = false;
            this.context = [];
            this.templateStarts = [];

            for (var i = 0; i < state.option.indent; i += 1) {
                state.tab += " ";
            }
            this.ignoreLinterErrors = false;
        }

        Lexer.prototype = {
            _lines: [],

            inContext: function(ctxType) {
                return this.context.length > 0 && this.context[this.context.length - 1].type === ctxType;
            },

            pushContext: function(ctxType) {
                this.context.push({ type: ctxType });
            },

            popContext: function() {
                return this.context.pop();
            },

            isContext: function(context) {
                return this.context.length > 0 && this.context[this.context.length - 1] === context;
            },

            currentContext: function() {
                return this.context.length > 0 && this.context[this.context.length - 1];
            },

            getLines: function() {
                this._lines = state.lines;
                return this._lines;
            },

            setLines: function(val) {
                this._lines = val;
                state.lines = this._lines;
            },
            peek: function(i) {
                return this.input.charAt(i || 0);
            },
            skip: function(i) {
                i = i || 1;
                this.char += i;
                this.input = this.input.slice(i);
            },
            on: function(names, listener) {
                names.split(" ").forEach(function(name) {
                    this.emitter.on(name, listener);
                }.bind(this));
            },
            trigger: function() {
                this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments));
            },
            triggerAsync: function(type, args, checks, fn) {
                checks.push(function() {
                    if (fn()) {
                        this.trigger(type, args);
                    }
                }.bind(this));
            },
            scanPunctuator: function() {
                var ch1 = this.peek();
                var ch2, ch3, ch4;

                switch (ch1) {
                    case ".":
                        if ((/^[0-9]$/).test(this.peek(1))) {
                            return null;
                        }
                        if (this.peek(1) === "." && this.peek(2) === ".") {
                            return {
                                type: Token.Punctuator,
                                value: "..."
                            };
                        }
                    case "(":
                    case ")":
                    case ";":
                    case ",":
                    case "[":
                    case "]":
                    case ":":
                    case "~":
                    case "?":
                        return {
                            type: Token.Punctuator,
                            value: ch1
                        };
                    case "{":
                        this.pushContext(Context.Block);
                        return {
                            type: Token.Punctuator,
                            value: ch1
                        };
                    case "}":
                        if (this.inContext(Context.Block)) {
                            this.popContext();
                        }
                        return {
                            type: Token.Punctuator,
                            value: ch1
                        };
                    case "#":
                        return {
                            type: Token.Punctuator,
                            value: ch1
                        };
                    case "":
                        return null;
                }

                ch2 = this.peek(1);
                ch3 = this.peek(2);
                ch4 = this.peek(3);

                if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") {
                    return {
                        type: Token.Punctuator,
                        value: ">>>="
                    };
                }

                if (ch1 === "=" && ch2 === "=" && ch3 === "=") {
                    return {
                        type: Token.Punctuator,
                        value: "==="
                    };
                }

                if (ch1 === "!" && ch2 === "=" && ch3 === "=") {
                    return {
                        type: Token.Punctuator,
                        value: "!=="
                    };
                }

                if (ch1 === ">" && ch2 === ">" && ch3 === ">") {
                    return {
                        type: Token.Punctuator,
                        value: ">>>"
                    };
                }

                if (ch1 === "<" && ch2 === "<" && ch3 === "=") {
                    return {
                        type: Token.Punctuator,
                        value: "<<="
                    };
                }

                if (ch1 === ">" && ch2 === ">" && ch3 === "=") {
                    return {
                        type: Token.Punctuator,
                        value: ">>="
                    };
                }
                if (ch1 === "=" && ch2 === ">") {
                    return {
                        type: Token.Punctuator,
                        value: ch1 + ch2
                    };
                }
                if (ch1 === ch2 && ("+-<>&|".indexOf(ch1) >= 0)) {
                    return {
                        type: Token.Punctuator,
                        value: ch1 + ch2
                    };
                }

                if ("<>=!+-*%&|^".indexOf(ch1) >= 0) {
                    if (ch2 === "=") {
                        return {
                            type: Token.Punctuator,
                            value: ch1 + ch2
                        };
                    }

                    return {
                        type: Token.Punctuator,
                        value: ch1
                    };
                }

                if (ch1 === "/") {
                    if (ch2 === "=") {
                        return {
                            type: Token.Punctuator,
                            value: "/="
                        };
                    }

                    return {
                        type: Token.Punctuator,
                        value: "/"
                    };
                }

                return null;
            },
            scanComments: function() {
                var ch1 = this.peek();
                var ch2 = this.peek(1);
                var rest = this.input.substr(2);
                var startLine = this.line;
                var startChar = this.char;
                var self = this;

                function commentToken(label, body, opt) {
                    var special = ["jshint", "jslint", "members", "member", "globals", "global", "exported"];
                    var isSpecial = false;
                    var value = label + body;
                    var commentType = "plain";
                    opt = opt || {};

                    if (opt.isMultiline) {
                        value += "*/";
                    }

                    body = body.replace(/\n/g, " ");

                    if (label === "/*" && reg.fallsThrough.test(body)) {
                        isSpecial = true;
                        commentType = "falls through";
                    }

                    special.forEach(function(str) {
                        if (isSpecial) {
                            return;
                        }
                        if (label === "//" && str !== "jshint") {
                            return;
                        }

                        if (body.charAt(str.length) === " " && body.substr(0, str.length) === str) {
                            isSpecial = true;
                            label = label + str;
                            body = body.substr(str.length);
                        }

                        if (!isSpecial && body.charAt(0) === " " && body.charAt(str.length + 1) === " " &&
                            body.substr(1, str.length) === str) {
                            isSpecial = true;
                            label = label + " " + str;
                            body = body.substr(str.length + 1);
                        }

                        if (!isSpecial) {
                            return;
                        }

                        switch (str) {
                            case "member":
                                commentType = "members";
                                break;
                            case "global":
                                commentType = "globals";
                                break;
                            default:
                                var options = body.split(":").map(function(v) {
                                    return v.replace(/^\s+/, "").replace(/\s+$/, "");
                                });

                                if (options.length === 2) {
                                    switch (options[0]) {
                                        case "ignore":
                                            switch (options[1]) {
                                                case "start":
                                                    self.ignoringLinterErrors = true;
                                                    isSpecial = false;
                                                    break;
                                                case "end":
                                                    self.ignoringLinterErrors = false;
                                                    isSpecial = false;
                                                    break;
                                            }
                                    }
                                }

                                commentType = str;
                        }
                    });

                    return {
                        type: Token.Comment,
                        commentType: commentType,
                        value: value,
                        body: body,
                        isSpecial: isSpecial,
                        isMultiline: opt.isMultiline || false,
                        isMalformed: opt.isMalformed || false
                    };
                }
                if (ch1 === "*" && ch2 === "/") {
                    this.trigger("error", {
                        code: "E018",
                        line: startLine,
                        character: startChar
                    });

                    this.skip(2);
                    return null;
                }
                if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) {
                    return null;
                }
                if (ch2 === "/") {
                    this.skip(this.input.length); // Skip to the EOL.
                    return commentToken("//", rest);
                }

                var body = "";
                if (ch2 === "*") {
                    this.inComment = true;
                    this.skip(2);

                    while (this.peek() !== "*" || this.peek(1) !== "/") {
                        if (this.peek() === "") { // End of Line
                            body += "\n";
                            if (!this.nextLine()) {
                                this.trigger("error", {
                                    code: "E017",
                                    line: startLine,
                                    character: startChar
                                });

                                this.inComment = false;
                                return commentToken("/*", body, {
                                    isMultiline: true,
                                    isMalformed: true
                                });
                            }
                        } else {
                            body += this.peek();
                            this.skip();
                        }
                    }

                    this.skip(2);
                    this.inComment = false;
                    return commentToken("/*", body, { isMultiline: true });
                }
            },
            scanKeyword: function() {
                var result = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input);
                var keywords = [
                    "if", "in", "do", "var", "for", "new",
                    "try", "let", "this", "else", "case",
                    "void", "with", "enum", "while", "break",
                    "catch", "throw", "const", "yield", "class",
                    "super", "return", "typeof", "delete",
                    "switch", "export", "import", "default",
                    "finally", "extends", "function", "continue",
                    "debugger", "instanceof"
                ];

                if (result && keywords.indexOf(result[0]) >= 0) {
                    return {
                        type: Token.Keyword,
                        value: result[0]
                    };
                }

                return null;
            },
            scanIdentifier: function() {
                var id = "";
                var index = 0;
                var type, char;

                function isNonAsciiIdentifierStart(code) {
                    return code > 256;
                }

                function isNonAsciiIdentifierPart(code) {
                    return code > 256;
                }

                function isHexDigit(str) {
                    return (/^[0-9a-fA-F]$/).test(str);
                }

                var readUnicodeEscapeSequence = function() {
                    index += 1;

                    if (this.peek(index) !== "u") {
                        return null;
                    }

                    var ch1 = this.peek(index + 1);
                    var ch2 = this.peek(index + 2);
                    var ch3 = this.peek(index + 3);
                    var ch4 = this.peek(index + 4);
                    var code;

                    if (isHexDigit(ch1) && isHexDigit(ch2) && isHexDigit(ch3) && isHexDigit(ch4)) {
                        code = parseInt(ch1 + ch2 + ch3 + ch4, 16);

                        if (asciiIdentifierPartTable[code] || isNonAsciiIdentifierPart(code)) {
                            index += 5;
                            return "\\u" + ch1 + ch2 + ch3 + ch4;
                        }

                        return null;
                    }

                    return null;
                }.bind(this);

                var getIdentifierStart = function() {
                    var chr = this.peek(index);
                    var code = chr.charCodeAt(0);

                    if (code === 92) {
                        return readUnicodeEscapeSequence();
                    }

                    if (code < 128) {
                        if (asciiIdentifierStartTable[code]) {
                            index += 1;
                            return chr;
                        }

                        return null;
                    }

                    if (isNonAsciiIdentifierStart(code)) {
                        index += 1;
                        return chr;
                    }

                    return null;
                }.bind(this);

                var getIdentifierPart = function() {
                    var chr = this.peek(index);
                    var code = chr.charCodeAt(0);

                    if (code === 92) {
                        return readUnicodeEscapeSequence();
                    }

                    if (code < 128) {
                        if (asciiIdentifierPartTable[code]) {
                            index += 1;
                            return chr;
                        }

                        return null;
                    }

                    if (isNonAsciiIdentifierPart(code)) {
                        index += 1;
                        return chr;
                    }

                    return null;
                }.bind(this);

                function removeEscapeSequences(id) {
                    return id.replace(/\\u([0-9a-fA-F]{4})/g, function(m0, codepoint) {
                        return String.fromCharCode(parseInt(codepoint, 16));
                    });
                }

                char = getIdentifierStart();
                if (char === null) {
                    return null;
                }

                id = char;
                for (;;) {
                    char = getIdentifierPart();

                    if (char === null) {
                        break;
                    }

                    id += char;
                }

                switch (id) {
                    case "true":
                    case "false":
                        type = Token.BooleanLiteral;
                        break;
                    case "null":
                        type = Token.NullLiteral;
                        break;
                    default:
                        type = Token.Identifier;
                }

                return {
                    type: type,
                    value: removeEscapeSequences(id),
                    text: id,
                    tokenLength: id.length
                };
            },
            scanNumericLiteral: function() {
                var index = 0;
                var value = "";
                var length = this.input.length;
                var char = this.peek(index);
                var bad;
                var isAllowedDigit = isDecimalDigit;
                var base = 10;
                var isLegacy = false;

                function isDecimalDigit(str) {
                    return (/^[0-9]$/).test(str);
                }

                function isOctalDigit(str) {
                    return (/^[0-7]$/).test(str);
                }

                function isBinaryDigit(str) {
                    return (/^[01]$/).test(str);
                }

                function isHexDigit(str) {
                    return (/^[0-9a-fA-F]$/).test(str);
                }

                function isIdentifierStart(ch) {
                    return (ch === "$") || (ch === "_") || (ch === "\\") ||
                        (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z");
                }

                if (char !== "." && !isDecimalDigit(char)) {
                    return null;
                }

                if (char !== ".") {
                    value = this.peek(index);
                    index += 1;
                    char = this.peek(index);

                    if (value === "0") {
                        if (char === "x" || char === "X") {
                            isAllowedDigit = isHexDigit;
                            base = 16;

                            index += 1;
                            value += char;
                        }
                        if (char === "o" || char === "O") {
                            isAllowedDigit = isOctalDigit;
                            base = 8;

                            if (!state.inES6(true)) {
                                this.trigger("warning", {
                                    code: "W119",
                                    line: this.line,
                                    character: this.char,
                                    data: [ "Octal integer literal", "6" ]
                                });
                            }

                            index += 1;
                            value += char;
                        }
                        if (char === "b" || char === "B") {
                            isAllowedDigit = isBinaryDigit;
                            base = 2;

                            if (!state.inES6(true)) {
                                this.trigger("warning", {
                                    code: "W119",
                                    line: this.line,
                                    character: this.char,
                                    data: [ "Binary integer literal", "6" ]
                                });
                            }

                            index += 1;
                            value += char;
                        }
                        if (isOctalDigit(char)) {
                            isAllowedDigit = isOctalDigit;
                            base = 8;
                            isLegacy = true;
                            bad = false;

                            index += 1;
                            value += char;
                        }

                        if (!isOctalDigit(char) && isDecimalDigit(char)) {
                            index += 1;
                            value += char;
                        }
                    }

                    while (index < length) {
                        char = this.peek(index);

                        if (isLegacy && isDecimalDigit(char)) {
                            bad = true;
                        } else if (!isAllowedDigit(char)) {
                            break;
                        }
                        value += char;
                        index += 1;
                    }

                    if (isAllowedDigit !== isDecimalDigit) {
                        if (!isLegacy && value.length <= 2) { // 0x
                            return {
                                type: Token.NumericLiteral,
                                value: value,
                                isMalformed: true
                            };
                        }

                        if (index < length) {
                            char = this.peek(index);
                            if (isIdentifierStart(char)) {
                                return null;
                            }
                        }

                        return {
                            type: Token.NumericLiteral,
                            value: value,
                            base: base,
                            isLegacy: isLegacy,
                            isMalformed: false
                        };
                    }
                }

                if (char === ".") {
                    value += char;
                    index += 1;

                    while (index < length) {
                        char = this.peek(index);
                        if (!isDecimalDigit(char)) {
                            break;
                        }
                        value += char;
                        index += 1;
                    }
                }

                if (char === "e" || char === "E") {
                    value += char;
                    index += 1;
                    char = this.peek(index);

                    if (char === "+" || char === "-") {
                        value += this.peek(index);
                        index += 1;
                    }

                    char = this.peek(index);
                    if (isDecimalDigit(char)) {
                        value += char;
                        index += 1;

                        while (index < length) {
                            char = this.peek(index);
                            if (!isDecimalDigit(char)) {
                                break;
                            }
                            value += char;
                            index += 1;
                        }
                    } else {
                        return null;
                    }
                }

                if (index < length) {
                    char = this.peek(index);
                    if (isIdentifierStart(char)) {
                        return null;
                    }
                }

                return {
                    type: Token.NumericLiteral,
                    value: value,
                    base: base,
                    isMalformed: !isFinite(value)
                };
            },
            scanEscapeSequence: function(checks) {
                var allowNewLine = false;
                var jump = 1;
                this.skip();
                var char = this.peek();

                switch (char) {
                    case "'":
                        this.triggerAsync("warning", {
                            code: "W114",
                            line: this.line,
                            character: this.char,
                            data: [ "\\'" ]
                        }, checks, function() {return state.jsonMode; });
                        break;
                    case "b":
                        char = "\\b";
                        break;
                    case "f":
                        char = "\\f";
                        break;
                    case "n":
                        char = "\\n";
                        break;
                    case "r":
                        char = "\\r";
                        break;
                    case "t":
                        char = "\\t";
                        break;
                    case "0":
                        char = "\\0";
                        var n = parseInt(this.peek(1), 10);
                        this.triggerAsync("warning", {
                                code: "W115",
                                line: this.line,
                                character: this.char
                            }, checks,
                            function() { return n >= 0 && n <= 7 && state.isStrict(); });
                        break;
                    case "u":
                        var hexCode = this.input.substr(1, 4);
                        var code = parseInt(hexCode, 16);
                        if (isNaN(code)) {
                            this.trigger("warning", {
                                code: "W052",
                                line: this.line,
                                character: this.char,
                                data: [ "u" + hexCode ]
                            });
                        }
                        char = String.fromCharCode(code);
                        jump = 5;
                        break;
                    case "v":
                        this.triggerAsync("warning", {
                            code: "W114",
                            line: this.line,
                            character: this.char,
                            data: [ "\\v" ]
                        }, checks, function() { return state.jsonMode; });

                        char = "\v";
                        break;
                    case "x":
                        var  x = parseInt(this.input.substr(1, 2), 16);

                        this.triggerAsync("warning", {
                            code: "W114",
                            line: this.line,
                            character: this.char,
                            data: [ "\\x-" ]
                        }, checks, function() { return state.jsonMode; });

                        char = String.fromCharCode(x);
                        jump = 3;
                        break;
                    case "\\":
                        char = "\\\\";
                        break;
                    case "\"":
                        char = "\\\"";
                        break;
                    case "/":
                        break;
                    case "":
                        allowNewLine = true;
                        char = "";
                        break;
                }

                return { char: char, jump: jump, allowNewLine: allowNewLine };
            },
            scanTemplateLiteral: function(checks) {
                var tokenType;
                var value = "";
                var ch;
                var startLine = this.line;
                var startChar = this.char;
                var depth = this.templateStarts.length;

                if (!state.inES6(true)) {
                    return null;
                } else if (this.peek() === "`") {
                    tokenType = Token.TemplateHead;
                    this.templateStarts.push({ line: this.line, char: this.char });
                    depth = this.templateStarts.length;
                    this.skip(1);
                    this.pushContext(Context.Template);
                } else if (this.inContext(Context.Template) && this.peek() === "}") {
                    tokenType = Token.TemplateMiddle;
                } else {
                    return null;
                }

                while (this.peek() !== "`") {
                    while ((ch = this.peek()) === "") {
                        value += "\n";
                        if (!this.nextLine()) {
                            var startPos = this.templateStarts.pop();
                            this.trigger("error", {
                                code: "E052",
                                line: startPos.line,
                                character: startPos.char
                            });
                            return {
                                type: tokenType,
                                value: value,
                                startLine: startLine,
                                startChar: startChar,
                                isUnclosed: true,
                                depth: depth,
                                context: this.popContext()
                            };
                        }
                    }

                    if (ch === '$' && this.peek(1) === '{') {
                        value += '${';
                        this.skip(2);
                        return {
                            type: tokenType,
                            value: value,
                            startLine: startLine,
                            startChar: startChar,
                            isUnclosed: false,
                            depth: depth,
                            context: this.currentContext()
                        };
                    } else if (ch === '\\') {
                        var escape = this.scanEscapeSequence(checks);
                        value += escape.char;
                        this.skip(escape.jump);
                    } else if (ch !== '`') {
                        value += ch;
                        this.skip(1);
                    }
                }
                tokenType = tokenType === Token.TemplateHead ? Token.NoSubstTemplate : Token.TemplateTail;
                this.skip(1);
                this.templateStarts.pop();

                return {
                    type: tokenType,
                    value: value,
                    startLine: startLine,
                    startChar: startChar,
                    isUnclosed: false,
                    depth: depth,
                    context: this.popContext()
                };
            },
            scanStringLiteral: function(checks) {
                var quote = this.peek();
                if (quote !== "\"" && quote !== "'") {
                    return null;
                }
                this.triggerAsync("warning", {
                    code: "W108",
                    line: this.line,
                    character: this.char // +1?
                }, checks, function() { return state.jsonMode && quote !== "\""; });

                var value = "";
                var startLine = this.line;
                var startChar = this.char;
                var allowNewLine = false;

                this.skip();

                while (this.peek() !== quote) {
                    if (this.peek() === "") { // End Of Line

                        if (!allowNewLine) {
                            this.trigger("warning", {
                                code: "W112",
                                line: this.line,
                                character: this.char
                            });
                        } else {
                            allowNewLine = false;

                            this.triggerAsync("warning", {
                                code: "W043",
                                line: this.line,
                                character: this.char
                            }, checks, function() { return !state.option.multistr; });

                            this.triggerAsync("warning", {
                                code: "W042",
                                line: this.line,
                                character: this.char
                            }, checks, function() { return state.jsonMode && state.option.multistr; });
                        }

                        if (!this.nextLine()) {
                            this.trigger("error", {
                                code: "E029",
                                line: startLine,
                                character: startChar
                            });

                            return {
                                type: Token.StringLiteral,
                                value: value,
                                startLine: startLine,
                                startChar: startChar,
                                isUnclosed: true,
                                quote: quote
                            };
                        }

                    } else { // Any character other than End Of Line

                        allowNewLine = false;
                        var char = this.peek();
                        var jump = 1; // A length of a jump, after we're done

                        if (char < " ") {
                            this.trigger("warning", {
                                code: "W113",
                                line: this.line,
                                character: this.char,
                                data: [ "<non-printable>" ]
                            });
                        }
                        if (char === "\\") {
                            var parsed = this.scanEscapeSequence(checks);
                            char = parsed.char;
                            jump = parsed.jump;
                            allowNewLine = parsed.allowNewLine;
                        }

                        value += char;
                        this.skip(jump);
                    }
                }

                this.skip();
                return {
                    type: Token.StringLiteral,
                    value: value,
                    startLine: startLine,
                    startChar: startChar,
                    isUnclosed: false,
                    quote: quote
                };
            },
            scanRegExp: function() {
                var index = 0;
                var length = this.input.length;
                var char = this.peek();
                var value = char;
                var body = "";
                var flags = [];
                var malformed = false;
                var isCharSet = false;
                var terminated;

                var scanUnexpectedChars = function() {
                    if (char < " ") {
                        malformed = true;
                        this.trigger("warning", {
                            code: "W048",
                            line: this.line,
                            character: this.char
                        });
                    }
                    if (char === "<") {
                        malformed = true;
                        this.trigger("warning", {
                            code: "W049",
                            line: this.line,
                            character: this.char,
                            data: [ char ]
                        });
                    }
                }.bind(this);
                if (!this.prereg || char !== "/") {
                    return null;
                }

                index += 1;
                terminated = false;

                while (index < length) {
                    char = this.peek(index);
                    value += char;
                    body += char;

                    if (isCharSet) {
                        if (char === "]") {
                            if (this.peek(index - 1) !== "\\" || this.peek(index - 2) === "\\") {
                                isCharSet = false;
                            }
                        }

                        if (char === "\\") {
                            index += 1;
                            char = this.peek(index);
                            body += char;
                            value += char;

                            scanUnexpectedChars();
                        }

                        index += 1;
                        continue;
                    }

                    if (char === "\\") {
                        index += 1;
                        char = this.peek(index);
                        body += char;
                        value += char;

                        scanUnexpectedChars();

                        if (char === "/") {
                            index += 1;
                            continue;
                        }

                        if (char === "[") {
                            index += 1;
                            continue;
                        }
                    }

                    if (char === "[") {
                        isCharSet = true;
                        index += 1;
                        continue;
                    }

                    if (char === "/") {
                        body = body.substr(0, body.length - 1);
                        terminated = true;
                        index += 1;
                        break;
                    }

                    index += 1;
                }

                if (!terminated) {
                    this.trigger("error", {
                        code: "E015",
                        line: this.line,
                        character: this.from
                    });

                    return void this.trigger("fatal", {
                        line: this.line,
                        from: this.from
                    });
                }

                while (index < length) {
                    char = this.peek(index);
                    if (!/[gim]/.test(char)) {
                        break;
                    }
                    flags.push(char);
                    value += char;
                    index += 1;
                }

                try {
                    new RegExp(body, flags.join(""));
                } catch (err) {
                    malformed = true;
                    this.trigger("error", {
                        code: "E016",
                        line: this.line,
                        character: this.char,
                        data: [ err.message ] // Platform dependent!
                    });
                }

                return {
                    type: Token.RegExp,
                    value: value,
                    flags: flags,
                    isMalformed: malformed
                };
            },
            scanNonBreakingSpaces: function() {
                return state.option.nonbsp ?
                    this.input.search(/(\u00A0)/) : -1;
            },
            scanUnsafeChars: function() {
                return this.input.search(reg.unsafeChars);
            },
            next: function(checks) {
                this.from = this.char;
                var start;
                if (/\s/.test(this.peek())) {
                    start = this.char;

                    while (/\s/.test(this.peek())) {
                        this.from += 1;
                        this.skip();
                    }
                }

                var match = this.scanComments() ||
                    this.scanStringLiteral(checks) ||
                    this.scanTemplateLiteral(checks);

                if (match) {
                    return match;
                }

                match =
                    this.scanRegExp() ||
                    this.scanPunctuator() ||
                    this.scanKeyword() ||
                    this.scanIdentifier() ||
                    this.scanNumericLiteral();

                if (match) {
                    this.skip(match.tokenLength || match.value.length);
                    return match;
                }

                return null;
            },
            nextLine: function() {
                var char;

                if (this.line >= this.getLines().length) {
                    return false;
                }

                this.input = this.getLines()[this.line];
                this.line += 1;
                this.char = 1;
                this.from = 1;

                var inputTrimmed = this.input.trim();

                var startsWith = function() {
                    return _.some(arguments, function(prefix) {
                        return inputTrimmed.indexOf(prefix) === 0;
                    });
                };

                var endsWith = function() {
                    return _.some(arguments, function(suffix) {
                        return inputTrimmed.indexOf(suffix, inputTrimmed.length - suffix.length) !== -1;
                    });
                };
                if (this.ignoringLinterErrors === true) {
                    if (!startsWith("/*", "//") && !(this.inComment && endsWith("*/"))) {
                        this.input = "";
                    }
                }

                char = this.scanNonBreakingSpaces();
                if (char >= 0) {
                    this.trigger("warning", { code: "W125", line: this.line, character: char + 1 });
                }

                this.input = this.input.replace(/\t/g, state.tab);
                char = this.scanUnsafeChars();

                if (char >= 0) {
                    this.trigger("warning", { code: "W100", line: this.line, character: char });
                }

                if (!this.ignoringLinterErrors && state.option.maxlen &&
                    state.option.maxlen < this.input.length) {
                    var inComment = this.inComment ||
                        startsWith.call(inputTrimmed, "//") ||
                        startsWith.call(inputTrimmed, "/*");

                    var shouldTriggerError = !inComment || !reg.maxlenException.test(inputTrimmed);

                    if (shouldTriggerError) {
                        this.trigger("warning", { code: "W101", line: this.line, character: this.input.length });
                    }
                }

                return true;
            },
            start: function() {
                this.nextLine();
            },
            token: function() {
                var checks = asyncTrigger();
                var token;


                function isReserved(token, isProperty) {
                    if (!token.reserved) {
                        return false;
                    }
                    var meta = token.meta;

                    if (meta && meta.isFutureReservedWord && state.inES5()) {
                        if (!meta.es5) {
                            return false;
                        }
                        if (meta.strictOnly) {
                            if (!state.option.strict && !state.isStrict()) {
                                return false;
                            }
                        }

                        if (isProperty) {
                            return false;
                        }
                    }

                    return true;
                }
                var create = function(type, value, isProperty, token) {
                    var obj;

                    if (type !== "(endline)" && type !== "(end)") {
                        this.prereg = false;
                    }

                    if (type === "(punctuator)") {
                        switch (value) {
                            case ".":
                            case ")":
                            case "~":
                            case "#":
                            case "]":
                            case "++":
                            case "--":
                                this.prereg = false;
                                break;
                            default:
                                this.prereg = true;
                        }

                        obj = Object.create(state.syntax[value] || state.syntax["(error)"]);
                    }

                    if (type === "(identifier)") {
                        if (value === "return" || value === "case" || value === "typeof") {
                            this.prereg = true;
                        }

                        if (_.has(state.syntax, value)) {
                            obj = Object.create(state.syntax[value] || state.syntax["(error)"]);
                            if (!isReserved(obj, isProperty && type === "(identifier)")) {
                                obj = null;
                            }
                        }
                    }

                    if (!obj) {
                        obj = Object.create(state.syntax[type]);
                    }

                    obj.identifier = (type === "(identifier)");
                    obj.type = obj.type || type;
                    obj.value = value;
                    obj.line = this.line;
                    obj.character = this.char;
                    obj.from = this.from;
                    if (obj.identifier && token) obj.raw_text = token.text || token.value;
                    if (token && token.startLine && token.startLine !== this.line) {
                        obj.startLine = token.startLine;
                    }
                    if (token && token.context) {
                        obj.context = token.context;
                    }
                    if (token && token.depth) {
                        obj.depth = token.depth;
                    }
                    if (token && token.isUnclosed) {
                        obj.isUnclosed = token.isUnclosed;
                    }

                    if (isProperty && obj.identifier) {
                        obj.isProperty = isProperty;
                    }

                    obj.check = checks.check;

                    return obj;
                }.bind(this);

                for (;;) {
                    if (!this.input.length) {
                        if (this.nextLine()) {
                            return create("(endline)", "");
                        }

                        if (this.exhausted) {
                            return null;
                        }

                        this.exhausted = true;
                        return create("(end)", "");
                    }

                    token = this.next(checks);

                    if (!token) {
                        if (this.input.length) {
                            this.trigger("error", {
                                code: "E024",
                                line: this.line,
                                character: this.char,
                                data: [ this.peek() ]
                            });

                            this.input = "";
                        }

                        continue;
                    }

                    switch (token.type) {
                        case Token.StringLiteral:
                            this.triggerAsync("String", {
                                line: this.line,
                                char: this.char,
                                from: this.from,
                                startLine: token.startLine,
                                startChar: token.startChar,
                                value: token.value,
                                quote: token.quote
                            }, checks, function() { return true; });

                            return create("(string)", token.value, null, token);

                        case Token.TemplateHead:
                            this.trigger("TemplateHead", {
                                line: this.line,
                                char: this.char,
                                from: this.from,
                                startLine: token.startLine,
                                startChar: token.startChar,
                                value: token.value
                            });
                            return create("(template)", token.value, null, token);

                        case Token.TemplateMiddle:
                            this.trigger("TemplateMiddle", {
                                line: this.line,
                                char: this.char,
                                from: this.from,
                                startLine: token.startLine,
                                startChar: token.startChar,
                                value: token.value
                            });
                            return create("(template middle)", token.value, null, token);

                        case Token.TemplateTail:
                            this.trigger("TemplateTail", {
                                line: this.line,
                                char: this.char,
                                from: this.from,
                                startLine: token.startLine,
                                startChar: token.startChar,
                                value: token.value
                            });
                            return create("(template tail)", token.value, null, token);

                        case Token.NoSubstTemplate:
                            this.trigger("NoSubstTemplate", {
                                line: this.line,
                                char: this.char,
                                from: this.from,
                                startLine: token.startLine,
                                startChar: token.startChar,
                                value: token.value
                            });
                            return create("(no subst template)", token.value, null, token);

                        case Token.Identifier:
                            this.triggerAsync("Identifier", {
                                line: this.line,
                                char: this.char,
                                from: this.form,
                                name: token.value,
                                raw_name: token.text,
                                isProperty: state.tokens.curr.id === "."
                            }, checks, function() { return true; });
                        case Token.Keyword:
                        case Token.NullLiteral:
                        case Token.BooleanLiteral:
                            return create("(identifier)", token.value, state.tokens.curr.id === ".", token);

                        case Token.NumericLiteral:
                            if (token.isMalformed) {
                                this.trigger("warning", {
                                    code: "W045",
                                    line: this.line,
                                    character: this.char,
                                    data: [ token.value ]
                                });
                            }

                            this.triggerAsync("warning", {
                                code: "W114",
                                line: this.line,
                                character: this.char,
                                data: [ "0x-" ]
                            }, checks, function() { return token.base === 16 && state.jsonMode; });

                            this.triggerAsync("warning", {
                                code: "W115",
                                line: this.line,
                                character: this.char
                            }, checks, function() {
                                return state.isStrict() && token.base === 8 && token.isLegacy;
                            });

                            this.trigger("Number", {
                                line: this.line,
                                char: this.char,
                                from: this.from,
                                value: token.value,
                                base: token.base,
                                isMalformed: token.malformed
                            });

                            return create("(number)", token.value);

                        case Token.RegExp:
                            return create("(regexp)", token.value);

                        case Token.Comment:
                            state.tokens.curr.comment = true;

                            if (token.isSpecial) {
                                return {
                                    id: '(comment)',
                                    value: token.value,
                                    body: token.body,
                                    type: token.commentType,
                                    isSpecial: token.isSpecial,
                                    line: this.line,
                                    character: this.char,
                                    from: this.from
                                };
                            }

                            break;

                        case "":
                            break;

                        default:
                            return create("(punctuator)", token.value);
                    }
                }
            }
        };

        exports.Lexer = Lexer;
        exports.Context = Context;

    },{"../data/ascii-identifier-data.js":"/node_modules/jshint/data/ascii-identifier-data.js","../lodash":"/node_modules/jshint/lodash.js","./reg.js":"/node_modules/jshint/src/reg.js","./state.js":"/node_modules/jshint/src/state.js","events":"/node_modules/browserify/node_modules/events/events.js"}],"/node_modules/jshint/src/messages.js":[function(_dereq_,module,exports){
        "use strict";

        var _ = _dereq_("../lodash");

        var errors = {
            E001: "Bad option: '{a}'.",
            E002: "Bad option value.",
            E003: "Expected a JSON value.",
            E004: "Input is neither a string nor an array of strings.",
            E005: "Input is empty.",
            E006: "Unexpected early end of program.",
            E007: "Missing \"use strict\" statement.",
            E008: "Strict violation.",
            E009: "Option 'validthis' can't be used in a global scope.",
            E010: "'with' is not allowed in strict mode.",
            E011: "'{a}' has already been declared.",
            E012: "const '{a}' is initialized to 'undefined'.",
            E013: "Attempting to override '{a}' which is a constant.",
            E014: "A regular expression literal can be confused with '/='.",
            E015: "Unclosed regular expression.",
            E016: "Invalid regular expression.",
            E017: "Unclosed comment.",
            E018: "Unbegun comment.",
            E019: "Unmatched '{a}'.",
            E020: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
            E021: "Expected '{a}' and instead saw '{b}'.",
            E022: "Line breaking error '{a}'.",
            E023: "Missing '{a}'.",
            E024: "Unexpected '{a}'.",
            E025: "Missing ':' on a case clause.",
            E026: "Missing '}' to match '{' from line {a}.",
            E027: "Missing ']' to match '[' from line {a}.",
            E028: "Illegal comma.",
            E029: "Unclosed string.",
            E030: "Expected an identifier and instead saw '{a}'.",
            E031: "Bad assignment.", // FIXME: Rephrase
            E032: "Expected a small integer or 'false' and instead saw '{a}'.",
            E033: "Expected an operator and instead saw '{a}'.",
            E034: "get/set are ES5 features.",
            E035: "Missing property name.",
            E036: "Expected to see a statement and instead saw a block.",
            E037: null,
            E038: null,
            E039: "Function declarations are not invocable. Wrap the whole function invocation in parens.",
            E040: "Each value should have its own case label.",
            E041: "Unrecoverable syntax error.",
            E042: "Stopping.",
            E043: "Too many errors.",
            E044: null,
            E045: "Invalid for each loop.",
            E046: "A yield statement shall be within a generator function (with syntax: `function*`)",
            E047: null,
            E048: "{a} declaration not directly within block.",
            E049: "A {a} cannot be named '{b}'.",
            E050: "Mozilla requires the yield expression to be parenthesized here.",
            E051: null,
            E052: "Unclosed template literal.",
            E053: "Export declaration must be in global scope.",
            E054: "Class properties must be methods. Expected '(' but instead saw '{a}'.",
            E055: "The '{a}' option cannot be set after any executable code.",
            E056: "'{a}' was used before it was declared, which is illegal for '{b}' variables.",
            E057: "Invalid meta property: '{a}.{b}'.",
            E058: "Missing semicolon."
        };

        var warnings = {
            W001: "'hasOwnProperty' is a really bad name.",
            W002: "Value of '{a}' may be overwritten in IE 8 and earlier.",
            W003: "'{a}' was used before it was defined.",
            W004: "'{a}' is already defined.",
            W005: "A dot following a number can be confused with a decimal point.",
            W006: "Confusing minuses.",
            W007: "Confusing plusses.",
            W008: "A leading decimal point can be confused with a dot: '{a}'.",
            W009: "The array literal notation [] is preferable.",
            W010: "The object literal notation {} is preferable.",
            W011: null,
            W012: null,
            W013: null,
            W014: "Bad line breaking before '{a}'.",
            W015: null,
            W016: "Unexpected use of '{a}'.",
            W017: "Bad operand.",
            W018: "Confusing use of '{a}'.",
            W019: "Use the isNaN function to compare with NaN.",
            W020: "Read only.",
            W021: "Reassignment of '{a}', which is is a {b}. " +
            "Use 'var' or 'let' to declare bindings that may change.",
            W022: "Do not assign to the exception parameter.",
            W023: "Expected an identifier in an assignment and instead saw a function invocation.",
            W024: "Expected an identifier and instead saw '{a}' (a reserved word).",
            W025: "Missing name in function declaration.",
            W026: "Inner functions should be listed at the top of the outer function.",
            W027: "Unreachable '{a}' after '{b}'.",
            W028: "Label '{a}' on {b} statement.",
            W030: "Expected an assignment or function call and instead saw an expression.",
            W031: "Do not use 'new' for side effects.",
            W032: "Unnecessary semicolon.",
            W033: "Missing semicolon.",
            W034: "Unnecessary directive \"{a}\".",
            W035: "Empty block.",
            W036: "Unexpected /*member '{a}'.",
            W037: "'{a}' is a statement label.",
            W038: "'{a}' used out of scope.",
            W039: "'{a}' is not allowed.",
            W040: "Possible strict violation.",
            W041: "Use '{a}' to compare with '{b}'.",
            W042: "Avoid EOL escaping.",
            W043: "Bad escaping of EOL. Use option multistr if needed.",
            W044: "Bad or unnecessary escaping.", /* TODO(caitp): remove W044 */
            W045: "Bad number '{a}'.",
            W046: "Don't use extra leading zeros '{a}'.",
            W047: "A trailing decimal point can be confused with a dot: '{a}'.",
            W048: "Unexpected control character in regular expression.",
            W049: "Unexpected escaped character '{a}' in regular expression.",
            W050: "JavaScript URL.",
            W051: "Variables should not be deleted.",
            W052: "Unexpected '{a}'.",
            W053: "Do not use {a} as a constructor.",
            W054: "The Function constructor is a form of eval.",
            W055: "A constructor name should start with an uppercase letter.",
            W056: "Bad constructor.",
            W057: "Weird construction. Is 'new' necessary?",
            W058: "Missing '()' invoking a constructor.",
            W059: "Avoid arguments.{a}.",
            W060: "document.write can be a form of eval.",
            W061: "eval can be harmful.",
            W062: "Wrap an immediate function invocation in parens " +
            "to assist the reader in understanding that the expression " +
            "is the result of a function, and not the function itself.",
            W063: "Math is not a function.",
            W064: "Missing 'new' prefix when invoking a constructor.",
            W065: "Missing radix parameter.",
            W066: "Implied eval. Consider passing a function instead of a string.",
            W067: "Bad invocation.",
            W068: "Wrapping non-IIFE function literals in parens is unnecessary.",
            W069: "['{a}'] is better written in dot notation.",
            W070: "Extra comma. (it breaks older versions of IE)",
            W071: "This function has too many statements. ({a})",
            W072: "This function has too many parameters. ({a})",
            W073: "Blocks are nested too deeply. ({a})",
            W074: "This function's cyclomatic complexity is too high. ({a})",
            W075: "Duplicate {a} '{b}'.",
            W076: "Unexpected parameter '{a}' in get {b} function.",
            W077: "Expected a single parameter in set {a} function.",
            W078: "Setter is defined without getter.",
            W079: "Redefinition of '{a}'.",
            W080: "It's not necessary to initialize '{a}' to 'undefined'.",
            W081: null,
            W082: "Function declarations should not be placed in blocks. " +
            "Use a function expression or move the statement to the top of " +
            "the outer function.",
            W083: "Don't make functions within a loop.",
            W084: "Assignment in conditional expression",
            W085: "Don't use 'with'.",
            W086: "Expected a 'break' statement before '{a}'.",
            W087: "Forgotten 'debugger' statement?",
            W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.",
            W089: "The body of a for in should be wrapped in an if statement to filter " +
            "unwanted properties from the prototype.",
            W090: "'{a}' is not a statement label.",
            W091: null,
            W093: "Did you mean to return a conditional instead of an assignment?",
            W094: "Unexpected comma.",
            W095: "Expected a string and instead saw {a}.",
            W096: "The '{a}' key may produce unexpected results.",
            W097: "Use the function form of \"use strict\".",
            W098: "'{a}' is defined but never used.",
            W099: null,
            W100: "This character may get silently deleted by one or more browsers.",
            W101: "Line is too long.",
            W102: null,
            W103: "The '{a}' property is deprecated.",
            W104: "'{a}' is available in ES{b} (use 'esversion: {b}') or Mozilla JS extensions (use moz).",
            W105: "Unexpected {a} in '{b}'.",
            W106: "Identifier '{a}' is not in camel case.",
            W107: "Script URL.",
            W108: "Strings must use doublequote.",
            W109: "Strings must use singlequote.",
            W110: "Mixed double and single quotes.",
            W112: "Unclosed string.",
            W113: "Control character in string: {a}.",
            W114: "Avoid {a}.",
            W115: "Octal literals are not allowed in strict mode.",
            W116: "Expected '{a}' and instead saw '{b}'.",
            W117: "'{a}' is not defined.",
            W118: "'{a}' is only available in Mozilla JavaScript extensions (use moz option).",
            W119: "'{a}' is only available in ES{b} (use 'esversion: {b}').",
            W120: "You might be leaking a variable ({a}) here.",
            W121: "Extending prototype of native object: '{a}'.",
            W122: "Invalid typeof value '{a}'",
            W123: "'{a}' is already defined in outer scope.",
            W124: "A generator function shall contain a yield statement.",
            W125: "This line contains non-breaking spaces: http://jshint.com/doc/options/#nonbsp",
            W126: "Unnecessary grouping operator.",
            W127: "Unexpected use of a comma operator.",
            W128: "Empty array elements require elision=true.",
            W129: "'{a}' is defined in a future version of JavaScript. Use a " +
            "different variable name to avoid migration issues.",
            W130: "Invalid element after rest element.",
            W131: "Invalid parameter after rest parameter.",
            W132: "`var` declarations are forbidden. Use `let` or `const` instead.",
            W133: "Invalid for-{a} loop left-hand-side: {b}.",
            W134: "The '{a}' option is only available when linting ECMAScript {b} code.",
            W135: "{a} may not be supported by non-browser environments.",
            W136: "'{a}' must be in function scope.",
            W137: "Empty destructuring.",
            W138: "Regular parameters should not come after default parameters."
        };

        var info = {
            I001: "Comma warnings can be turned off with 'laxcomma'.",
            I002: null,
            I003: "ES5 option is now set per default"
        };

        exports.errors = {};
        exports.warnings = {};
        exports.info = {};

        _.each(errors, function(desc, code) {
            exports.errors[code] = { code: code, desc: desc };
        });

        _.each(warnings, function(desc, code) {
            exports.warnings[code] = { code: code, desc: desc };
        });

        _.each(info, function(desc, code) {
            exports.info[code] = { code: code, desc: desc };
        });

    },{"../lodash":"/node_modules/jshint/lodash.js"}],"/node_modules/jshint/src/name-stack.js":[function(_dereq_,module,exports){
        "use strict";

        function NameStack() {
            this._stack = [];
        }

        Object.defineProperty(NameStack.prototype, "length", {
            get: function() {
                return this._stack.length;
            }
        });
        NameStack.prototype.push = function() {
            this._stack.push(null);
        };
        NameStack.prototype.pop = function() {
            this._stack.pop();
        };
        NameStack.prototype.set = function(token) {
            this._stack[this.length - 1] = token;
        };
        NameStack.prototype.infer = function() {
            var nameToken = this._stack[this.length - 1];
            var prefix = "";
            var type;
            if (!nameToken || nameToken.type === "class") {
                nameToken = this._stack[this.length - 2];
            }

            if (!nameToken) {
                return "(empty)";
            }

            type = nameToken.type;

            if (type !== "(string)" && type !== "(number)" && type !== "(identifier)" && type !== "default") {
                return "(expression)";
            }

            if (nameToken.accessorType) {
                prefix = nameToken.accessorType + " ";
            }

            return prefix + nameToken.value;
        };

        module.exports = NameStack;

    },{}],"/node_modules/jshint/src/options.js":[function(_dereq_,module,exports){
        "use strict";
        exports.bool = {
            enforcing: {
                bitwise     : true,
                freeze      : true,
                camelcase   : true,
                curly       : true,
                eqeqeq      : true,
                futurehostile: true,
                notypeof    : true,
                es3         : true,
                es5         : true,
                forin       : true,
                funcscope   : true,
                immed       : true,
                iterator    : true,
                newcap      : true,
                noarg       : true,
                nocomma     : true,
                noempty     : true,
                nonbsp      : true,
                nonew       : true,
                undef       : true,
                singleGroups: false,
                varstmt: false,
                enforceall : false
            },
            relaxing: {
                asi         : true,
                multistr    : true,
                debug       : true,
                boss        : true,
                evil        : true,
                globalstrict: true,
                plusplus    : true,
                proto       : true,
                scripturl   : true,
                sub         : true,
                supernew    : true,
                laxbreak    : true,
                laxcomma    : true,
                validthis   : true,
                withstmt    : true,
                moz         : true,
                noyield     : true,
                eqnull      : true,
                lastsemic   : true,
                loopfunc    : true,
                expr        : true,
                esnext      : true,
                elision     : true,
            },
            environments: {
                mootools    : true,
                couch       : true,
                jasmine     : true,
                jquery      : true,
                node        : true,
                qunit       : true,
                rhino       : true,
                shelljs     : true,
                prototypejs : true,
                yui         : true,
                mocha       : true,
                module      : true,
                wsh         : true,
                worker      : true,
                nonstandard : true,
                browser     : true,
                browserify  : true,
                devel       : true,
                dojo        : true,
                typed       : true,
                phantom     : true
            },
            obsolete: {
                onecase     : true, // if one case switch statements should be allowed
                regexp      : true, // if the . should not be allowed in regexp literals
                regexdash   : true  // if unescaped first/last dash (-) inside brackets
            }
        };
        exports.val = {
            maxlen       : false,
            indent       : false,
            maxerr       : false,
            predef       : false,
            globals      : false,
            quotmark     : false,

            scope        : false,
            maxstatements: false,
            maxdepth     : false,
            maxparams    : false,
            maxcomplexity: false,
            shadow       : false,
            strict      : true,
            unused       : true,
            latedef      : false,

            ignore       : false, // start/end ignoring lines of code, bypassing the lexer

            ignoreDelimiters: false, // array of start/end delimiters used to ignore
            esversion: 5
        };
        exports.inverted = {
            bitwise : true,
            forin   : true,
            newcap  : true,
            plusplus: true,
            regexp  : true,
            undef   : true,
            eqeqeq  : true,
            strict  : true
        };

        exports.validNames = Object.keys(exports.val)
            .concat(Object.keys(exports.bool.relaxing))
            .concat(Object.keys(exports.bool.enforcing))
            .concat(Object.keys(exports.bool.obsolete))
            .concat(Object.keys(exports.bool.environments));
        exports.renamed = {
            eqeq   : "eqeqeq",
            windows: "wsh",
            sloppy : "strict"
        };

        exports.removed = {
            nomen: true,
            onevar: true,
            passfail: true,
            white: true,
            gcl: true,
            smarttabs: true,
            trailing: true
        };
        exports.noenforceall = {
            varstmt: true,
            strict: true
        };

    },{}],"/node_modules/jshint/src/reg.js":[function(_dereq_,module,exports){

        "use strict";
        exports.unsafeString =
            /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;
        exports.unsafeChars =
            /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
        exports.needEsc =
            /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;

        exports.needEscGlobal =
            /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
        exports.starSlash = /\*\//;
        exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;
        exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i;
        exports.fallsThrough = /^\s*falls?\sthrough\s*$/;
        exports.maxlenException = /^(?:(?:\/\/|\/\*|\*) ?)?[^ ]+$/;

    },{}],"/node_modules/jshint/src/scope-manager.js":[function(_dereq_,module,exports){
        "use strict";

        var _      = _dereq_("../lodash");
        var events = _dereq_("events");
        var marker = {};
        var scopeManager = function(state, predefined, exported, declared) {

            var _current;
            var _scopeStack = [];

            function _newScope(type) {
                _current = {
                    "(labels)": Object.create(null),
                    "(usages)": Object.create(null),
                    "(breakLabels)": Object.create(null),
                    "(parent)": _current,
                    "(type)": type,
                    "(params)": (type === "functionparams" || type === "catchparams") ? [] : null
                };
                _scopeStack.push(_current);
            }

            _newScope("global");
            _current["(predefined)"] = predefined;

            var _currentFunctBody = _current; // this is the block after the params = function

            var usedPredefinedAndGlobals = Object.create(null);
            var impliedGlobals = Object.create(null);
            var unuseds = [];
            var emitter = new events.EventEmitter();

            function warning(code, token) {
                emitter.emit("warning", {
                    code: code,
                    token: token,
                    data: _.slice(arguments, 2)
                });
            }

            function error(code, token) {
                emitter.emit("warning", {
                    code: code,
                    token: token,
                    data: _.slice(arguments, 2)
                });
            }

            function _setupUsages(labelName) {
                if (!_current["(usages)"][labelName]) {
                    _current["(usages)"][labelName] = {
                        "(modified)": [],
                        "(reassigned)": [],
                        "(tokens)": []
                    };
                }
            }

            var _getUnusedOption = function(unused_opt) {
                if (unused_opt === undefined) {
                    unused_opt = state.option.unused;
                }

                if (unused_opt === true) {
                    unused_opt = "last-param";
                }

                return unused_opt;
            };

            var _warnUnused = function(name, tkn, type, unused_opt) {
                var line = tkn.line;
                var chr  = tkn.from;
                var raw_name = tkn.raw_text || name;

                unused_opt = _getUnusedOption(unused_opt);

                var warnable_types = {
                    "vars": ["var"],
                    "last-param": ["var", "param"],
                    "strict": ["var", "param", "last-param"]
                };

                if (unused_opt) {
                    if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) {
                        warning("W098", { line: line, from: chr }, raw_name);
                    }
                }
                if (unused_opt || type === "var") {
                    unuseds.push({
                        name: name,
                        line: line,
                        character: chr
                    });
                }
            };
            function _checkForUnused() {
                if (_current["(type)"] === "functionparams") {
                    _checkParams();
                    return;
                }
                var curentLabels = _current["(labels)"];
                for (var labelName in curentLabels) {
                    if (curentLabels[labelName]) {
                        if (curentLabels[labelName]["(type)"] !== "exception" &&
                            curentLabels[labelName]["(unused)"]) {
                            _warnUnused(labelName, curentLabels[labelName]["(token)"], "var");
                        }
                    }
                }
            }
            function _checkParams() {
                var params = _current["(params)"];

                if (!params) {
                    return;
                }

                var param = params.pop();
                var unused_opt;

                while (param) {
                    var label = _current["(labels)"][param];

                    unused_opt = _getUnusedOption(state.funct["(unusedOption)"]);
                    if (param === "undefined")
                        return;

                    if (label["(unused)"]) {
                        _warnUnused(param, label["(token)"], "param", state.funct["(unusedOption)"]);
                    } else if (unused_opt === "last-param") {
                        return;
                    }

                    param = params.pop();
                }
            }
            function _getLabel(labelName) {
                for (var i = _scopeStack.length - 1 ; i >= 0; --i) {
                    var scopeLabels = _scopeStack[i]["(labels)"];
                    if (scopeLabels[labelName]) {
                        return scopeLabels;
                    }
                }
            }

            function usedSoFarInCurrentFunction(labelName) {
                for (var i = _scopeStack.length - 1; i >= 0; i--) {
                    var current = _scopeStack[i];
                    if (current["(usages)"][labelName]) {
                        return current["(usages)"][labelName];
                    }
                    if (current === _currentFunctBody) {
                        break;
                    }
                }
                return false;
            }

            function _checkOuterShadow(labelName, token) {
                if (state.option.shadow !== "outer") {
                    return;
                }

                var isGlobal = _currentFunctBody["(type)"] === "global",
                    isNewFunction = _current["(type)"] === "functionparams";

                var outsideCurrentFunction = !isGlobal;
                for (var i = 0; i < _scopeStack.length; i++) {
                    var stackItem = _scopeStack[i];

                    if (!isNewFunction && _scopeStack[i + 1] === _currentFunctBody) {
                        outsideCurrentFunction = false;
                    }
                    if (outsideCurrentFunction && stackItem["(labels)"][labelName]) {
                        warning("W123", token, labelName);
                    }
                    if (stackItem["(breakLabels)"][labelName]) {
                        warning("W123", token, labelName);
                    }
                }
            }

            function _latedefWarning(type, labelName, token) {
                if (state.option.latedef) {
                    if ((state.option.latedef === true && type === "function") ||
                        type !== "function") {
                        warning("W003", token, labelName);
                    }
                }
            }

            var scopeManagerInst = {

                on: function(names, listener) {
                    names.split(" ").forEach(function(name) {
                        emitter.on(name, listener);
                    });
                },

                isPredefined: function(labelName) {
                    return !this.has(labelName) && _.has(_scopeStack[0]["(predefined)"], labelName);
                },
                stack: function(type) {
                    var previousScope = _current;
                    _newScope(type);

                    if (!type && previousScope["(type)"] === "functionparams") {

                        _current["(isFuncBody)"] = true;
                        _current["(context)"] = _currentFunctBody;
                        _currentFunctBody = _current;
                    }
                },

                unstack: function() {
                    var subScope = _scopeStack.length > 1 ? _scopeStack[_scopeStack.length - 2] : null;
                    var isUnstackingFunctionBody = _current === _currentFunctBody,
                        isUnstackingFunctionParams = _current["(type)"] === "functionparams",
                        isUnstackingFunctionOuter = _current["(type)"] === "functionouter";

                    var i, j;
                    var currentUsages = _current["(usages)"];
                    var currentLabels = _current["(labels)"];
                    var usedLabelNameList = Object.keys(currentUsages);

                    if (currentUsages.__proto__ && usedLabelNameList.indexOf("__proto__") === -1) {
                        usedLabelNameList.push("__proto__");
                    }

                    for (i = 0; i < usedLabelNameList.length; i++) {
                        var usedLabelName = usedLabelNameList[i];

                        var usage = currentUsages[usedLabelName];
                        var usedLabel = currentLabels[usedLabelName];
                        if (usedLabel) {
                            var usedLabelType = usedLabel["(type)"];

                            if (usedLabel["(useOutsideOfScope)"] && !state.option.funcscope) {
                                var usedTokens = usage["(tokens)"];
                                if (usedTokens) {
                                    for (j = 0; j < usedTokens.length; j++) {
                                        if (usedLabel["(function)"] === usedTokens[j]["(function)"]) {
                                            error("W038", usedTokens[j], usedLabelName);
                                        }
                                    }
                                }
                            }
                            _current["(labels)"][usedLabelName]["(unused)"] = false;
                            if (usedLabelType === "const" && usage["(modified)"]) {
                                for (j = 0; j < usage["(modified)"].length; j++) {
                                    error("E013", usage["(modified)"][j], usedLabelName);
                                }
                            }
                            if ((usedLabelType === "function" || usedLabelType === "class") &&
                                usage["(reassigned)"]) {
                                for (j = 0; j < usage["(reassigned)"].length; j++) {
                                    error("W021", usage["(reassigned)"][j], usedLabelName, usedLabelType);
                                }
                            }
                            continue;
                        }

                        if (isUnstackingFunctionOuter) {
                            state.funct["(isCapturing)"] = true;
                        }

                        if (subScope) {
                            if (!subScope["(usages)"][usedLabelName]) {
                                subScope["(usages)"][usedLabelName] = usage;
                                if (isUnstackingFunctionBody) {
                                    subScope["(usages)"][usedLabelName]["(onlyUsedSubFunction)"] = true;
                                }
                            } else {
                                var subScopeUsage = subScope["(usages)"][usedLabelName];
                                subScopeUsage["(modified)"] = subScopeUsage["(modified)"].concat(usage["(modified)"]);
                                subScopeUsage["(tokens)"] = subScopeUsage["(tokens)"].concat(usage["(tokens)"]);
                                subScopeUsage["(reassigned)"] =
                                    subScopeUsage["(reassigned)"].concat(usage["(reassigned)"]);
                                subScopeUsage["(onlyUsedSubFunction)"] = false;
                            }
                        } else {
                            if (typeof _current["(predefined)"][usedLabelName] === "boolean") {
                                delete declared[usedLabelName];
                                usedPredefinedAndGlobals[usedLabelName] = marker;
                                if (_current["(predefined)"][usedLabelName] === false && usage["(reassigned)"]) {
                                    for (j = 0; j < usage["(reassigned)"].length; j++) {
                                        warning("W020", usage["(reassigned)"][j]);
                                    }
                                }
                            }
                            else {
                                if (usage["(tokens)"]) {
                                    for (j = 0; j < usage["(tokens)"].length; j++) {
                                        var undefinedToken = usage["(tokens)"][j];
                                        if (!undefinedToken.forgiveUndef) {
                                            if (state.option.undef && !undefinedToken.ignoreUndef) {
                                                warning("W117", undefinedToken, usedLabelName);
                                            }
                                            if (impliedGlobals[usedLabelName]) {
                                                impliedGlobals[usedLabelName].line.push(undefinedToken.line);
                                            } else {
                                                impliedGlobals[usedLabelName] = {
                                                    name: usedLabelName,
                                                    line: [undefinedToken.line]
                                                };
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if (!subScope) {
                        Object.keys(declared)
                            .forEach(function(labelNotUsed) {
                                _warnUnused(labelNotUsed, declared[labelNotUsed], "var");
                            });
                    }
                    if (subScope && !isUnstackingFunctionBody &&
                        !isUnstackingFunctionParams && !isUnstackingFunctionOuter) {
                        var labelNames = Object.keys(currentLabels);
                        for (i = 0; i < labelNames.length; i++) {

                            var defLabelName = labelNames[i];
                            if (!currentLabels[defLabelName]["(blockscoped)"] &&
                                currentLabels[defLabelName]["(type)"] !== "exception" &&
                                !this.funct.has(defLabelName, { excludeCurrent: true })) {
                                subScope["(labels)"][defLabelName] = currentLabels[defLabelName];
                                if (_currentFunctBody["(type)"] !== "global") {
                                    subScope["(labels)"][defLabelName]["(useOutsideOfScope)"] = true;
                                }
                                delete currentLabels[defLabelName];
                            }
                        }
                    }

                    _checkForUnused();

                    _scopeStack.pop();
                    if (isUnstackingFunctionBody) {
                        _currentFunctBody = _scopeStack[_.findLastIndex(_scopeStack, function(scope) {
                            return scope["(isFuncBody)"] || scope["(type)"] === "global";
                        })];
                    }

                    _current = subScope;
                },
                addParam: function(labelName, token, type) {
                    type = type || "param";

                    if (type === "exception") {
                        var previouslyDefinedLabelType = this.funct.labeltype(labelName);
                        if (previouslyDefinedLabelType && previouslyDefinedLabelType !== "exception") {
                            if (!state.option.node) {
                                warning("W002", state.tokens.next, labelName);
                            }
                        }
                    }
                    if (_.has(_current["(labels)"], labelName)) {
                        _current["(labels)"][labelName].duplicated = true;
                    } else {
                        _checkOuterShadow(labelName, token, type);

                        _current["(labels)"][labelName] = {
                            "(type)" : type,
                            "(token)": token,
                            "(unused)": true };

                        _current["(params)"].push(labelName);
                    }

                    if (_.has(_current["(usages)"], labelName)) {
                        var usage = _current["(usages)"][labelName];
                        if (usage["(onlyUsedSubFunction)"]) {
                            _latedefWarning(type, labelName, token);
                        } else {
                            warning("E056", token, labelName, type);
                        }
                    }
                },

                validateParams: function() {
                    if (_currentFunctBody["(type)"] === "global") {
                        return;
                    }

                    var isStrict = state.isStrict();
                    var currentFunctParamScope = _currentFunctBody["(parent)"];

                    if (!currentFunctParamScope["(params)"]) {
                        return;
                    }

                    currentFunctParamScope["(params)"].forEach(function(labelName) {
                        var label = currentFunctParamScope["(labels)"][labelName];

                        if (label && label.duplicated) {
                            if (isStrict) {
                                warning("E011", label["(token)"], labelName);
                            } else if (state.option.shadow !== true) {
                                warning("W004", label["(token)"], labelName);
                            }
                        }
                    });
                },

                getUsedOrDefinedGlobals: function() {
                    var list = Object.keys(usedPredefinedAndGlobals);
                    if (usedPredefinedAndGlobals.__proto__ === marker &&
                        list.indexOf("__proto__") === -1) {
                        list.push("__proto__");
                    }

                    return list;
                },
                getImpliedGlobals: function() {
                    var values = _.values(impliedGlobals);
                    var hasProto = false;
                    if (impliedGlobals.__proto__) {
                        hasProto = values.some(function(value) {
                            return value.name === "__proto__";
                        });

                        if (!hasProto) {
                            values.push(impliedGlobals.__proto__);
                        }
                    }

                    return values;
                },
                getUnuseds: function() {
                    return unuseds;
                },

                has: function(labelName) {
                    return Boolean(_getLabel(labelName));
                },

                labeltype: function(labelName) {
                    var scopeLabels = _getLabel(labelName);
                    if (scopeLabels) {
                        return scopeLabels[labelName]["(type)"];
                    }
                    return null;
                },
                addExported: function(labelName) {
                    var globalLabels = _scopeStack[0]["(labels)"];
                    if (_.has(declared, labelName)) {
                        delete declared[labelName];
                    } else if (_.has(globalLabels, labelName)) {
                        globalLabels[labelName]["(unused)"] = false;
                    } else {
                        for (var i = 1; i < _scopeStack.length; i++) {
                            var scope = _scopeStack[i];
                            if (!scope["(type)"]) {
                                if (_.has(scope["(labels)"], labelName) &&
                                    !scope["(labels)"][labelName]["(blockscoped)"]) {
                                    scope["(labels)"][labelName]["(unused)"] = false;
                                    return;
                                }
                            } else {
                                break;
                            }
                        }
                        exported[labelName] = true;
                    }
                },
                setExported: function(labelName, token) {
                    this.block.use(labelName, token);
                },
                addlabel: function(labelName, opts) {

                    var type  = opts.type;
                    var token = opts.token;
                    var isblockscoped = type === "let" || type === "const" || type === "class";
                    var isexported    = (isblockscoped ? _current : _currentFunctBody)["(type)"] === "global" &&
                        _.has(exported, labelName);
                    _checkOuterShadow(labelName, token, type);
                    if (isblockscoped) {

                        var declaredInCurrentScope = _current["(labels)"][labelName];
                        if (!declaredInCurrentScope && _current === _currentFunctBody &&
                            _current["(type)"] !== "global") {
                            declaredInCurrentScope = !!_currentFunctBody["(parent)"]["(labels)"][labelName];
                        }
                        if (!declaredInCurrentScope && _current["(usages)"][labelName]) {
                            var usage = _current["(usages)"][labelName];
                            if (usage["(onlyUsedSubFunction)"]) {
                                _latedefWarning(type, labelName, token);
                            } else {
                                warning("E056", token, labelName, type);
                            }
                        }
                        if (declaredInCurrentScope) {
                            warning("E011", token, labelName);
                        }
                        else if (state.option.shadow === "outer") {
                            if (scopeManagerInst.funct.has(labelName)) {
                                warning("W004", token, labelName);
                            }
                        }

                        scopeManagerInst.block.add(labelName, type, token, !isexported);

                    } else {

                        var declaredInCurrentFunctionScope = scopeManagerInst.funct.has(labelName);
                        if (!declaredInCurrentFunctionScope && usedSoFarInCurrentFunction(labelName)) {
                            _latedefWarning(type, labelName, token);
                        }
                        if (scopeManagerInst.funct.has(labelName, { onlyBlockscoped: true })) {
                            warning("E011", token, labelName);
                        } else if (state.option.shadow !== true) {
                            if (declaredInCurrentFunctionScope && labelName !== "__proto__") {
                                if (_currentFunctBody["(type)"] !== "global") {
                                    warning("W004", token, labelName);
                                }
                            }
                        }

                        scopeManagerInst.funct.add(labelName, type, token, !isexported);

                        if (_currentFunctBody["(type)"] === "global") {
                            usedPredefinedAndGlobals[labelName] = marker;
                        }
                    }
                },

                funct: {
                    labeltype: function(labelName, options) {
                        var onlyBlockscoped = options && options.onlyBlockscoped;
                        var excludeParams = options && options.excludeParams;
                        var currentScopeIndex = _scopeStack.length - (options && options.excludeCurrent ? 2 : 1);
                        for (var i = currentScopeIndex; i >= 0; i--) {
                            var current = _scopeStack[i];
                            if (current["(labels)"][labelName] &&
                                (!onlyBlockscoped || current["(labels)"][labelName]["(blockscoped)"])) {
                                return current["(labels)"][labelName]["(type)"];
                            }
                            var scopeCheck = excludeParams ? _scopeStack[ i - 1 ] : current;
                            if (scopeCheck && scopeCheck["(type)"] === "functionparams") {
                                return null;
                            }
                        }
                        return null;
                    },
                    hasBreakLabel: function(labelName) {
                        for (var i = _scopeStack.length - 1; i >= 0; i--) {
                            var current = _scopeStack[i];

                            if (current["(breakLabels)"][labelName]) {
                                return true;
                            }
                            if (current["(type)"] === "functionparams") {
                                return false;
                            }
                        }
                        return false;
                    },
                    has: function(labelName, options) {
                        return Boolean(this.labeltype(labelName, options));
                    },
                    add: function(labelName, type, tok, unused) {
                        _current["(labels)"][labelName] = {
                            "(type)" : type,
                            "(token)": tok,
                            "(blockscoped)": false,
                            "(function)": _currentFunctBody,
                            "(unused)": unused };
                    }
                },

                block: {
                    isGlobal: function() {
                        return _current["(type)"] === "global";
                    },

                    use: function(labelName, token) {
                        var paramScope = _currentFunctBody["(parent)"];
                        if (paramScope && paramScope["(labels)"][labelName] &&
                            paramScope["(labels)"][labelName]["(type)"] === "param") {
                            if (!scopeManagerInst.funct.has(labelName,
                                    { excludeParams: true, onlyBlockscoped: true })) {
                                paramScope["(labels)"][labelName]["(unused)"] = false;
                            }
                        }

                        if (token && (state.ignored.W117 || state.option.undef === false)) {
                            token.ignoreUndef = true;
                        }

                        _setupUsages(labelName);

                        if (token) {
                            token["(function)"] = _currentFunctBody;
                            _current["(usages)"][labelName]["(tokens)"].push(token);
                        }
                    },

                    reassign: function(labelName, token) {

                        this.modify(labelName, token);

                        _current["(usages)"][labelName]["(reassigned)"].push(token);
                    },

                    modify: function(labelName, token) {

                        _setupUsages(labelName);

                        _current["(usages)"][labelName]["(modified)"].push(token);
                    },
                    add: function(labelName, type, tok, unused) {
                        _current["(labels)"][labelName] = {
                            "(type)" : type,
                            "(token)": tok,
                            "(blockscoped)": true,
                            "(unused)": unused };
                    },

                    addBreakLabel: function(labelName, opts) {
                        var token = opts.token;
                        if (scopeManagerInst.funct.hasBreakLabel(labelName)) {
                            warning("E011", token, labelName);
                        }
                        else if (state.option.shadow === "outer") {
                            if (scopeManagerInst.funct.has(labelName)) {
                                warning("W004", token, labelName);
                            } else {
                                _checkOuterShadow(labelName, token);
                            }
                        }
                        _current["(breakLabels)"][labelName] = token;
                    }
                }
            };
            return scopeManagerInst;
        };

        module.exports = scopeManager;

    },{"../lodash":"/node_modules/jshint/lodash.js","events":"/node_modules/browserify/node_modules/events/events.js"}],"/node_modules/jshint/src/state.js":[function(_dereq_,module,exports){
        "use strict";
        var NameStack = _dereq_("./name-stack.js");

        var state = {
            syntax: {},
            isStrict: function() {
                return this.directive["use strict"] || this.inClassBody ||
                    this.option.module || this.option.strict === "implied";
            },

            inMoz: function() {
                return this.option.moz;
            },
            inES6: function() {
                return this.option.moz || this.option.esversion >= 6;
            },
            inES5: function(strict) {
                if (strict) {
                    return (!this.option.esversion || this.option.esversion === 5) && !this.option.moz;
                }
                return !this.option.esversion || this.option.esversion >= 5 || this.option.moz;
            },


            reset: function() {
                this.tokens = {
                    prev: null,
                    next: null,
                    curr: null
                };

                this.option = {};
                this.funct = null;
                this.ignored = {};
                this.directive = {};
                this.jsonMode = false;
                this.jsonWarnings = [];
                this.lines = [];
                this.tab = "";
                this.cache = {}; // Node.JS doesn't have Map. Sniff.
                this.ignoredLines = {};
                this.forinifcheckneeded = false;
                this.nameStack = new NameStack();
                this.inClassBody = false;
            }
        };

        exports.state = state;

    },{"./name-stack.js":"/node_modules/jshint/src/name-stack.js"}],"/node_modules/jshint/src/style.js":[function(_dereq_,module,exports){
        "use strict";

        exports.register = function(linter) {

            linter.on("Identifier", function style_scanProto(data) {
                if (linter.getOption("proto")) {
                    return;
                }

                if (data.name === "__proto__") {
                    linter.warn("W103", {
                        line: data.line,
                        char: data.char,
                        data: [ data.name, "6" ]
                    });
                }
            });

            linter.on("Identifier", function style_scanIterator(data) {
                if (linter.getOption("iterator")) {
                    return;
                }

                if (data.name === "__iterator__") {
                    linter.warn("W103", {
                        line: data.line,
                        char: data.char,
                        data: [ data.name ]
                    });
                }
            });

            linter.on("Identifier", function style_scanCamelCase(data) {
                if (!linter.getOption("camelcase")) {
                    return;
                }

                if (data.name.replace(/^_+|_+$/g, "").indexOf("_") > -1 && !data.name.match(/^[A-Z0-9_]*$/)) {
                    linter.warn("W106", {
                        line: data.line,
                        char: data.from,
                        data: [ data.name ]
                    });
                }
            });

            linter.on("String", function style_scanQuotes(data) {
                var quotmark = linter.getOption("quotmark");
                var code;

                if (!quotmark) {
                    return;
                }

                if (quotmark === "single" && data.quote !== "'") {
                    code = "W109";
                }

                if (quotmark === "double" && data.quote !== "\"") {
                    code = "W108";
                }

                if (quotmark === true) {
                    if (!linter.getCache("quotmark")) {
                        linter.setCache("quotmark", data.quote);
                    }

                    if (linter.getCache("quotmark") !== data.quote) {
                        code = "W110";
                    }
                }

                if (code) {
                    linter.warn(code, {
                        line: data.line,
                        char: data.char,
                    });
                }
            });

            linter.on("Number", function style_scanNumbers(data) {
                if (data.value.charAt(0) === ".") {
                    linter.warn("W008", {
                        line: data.line,
                        char: data.char,
                        data: [ data.value ]
                    });
                }

                if (data.value.substr(data.value.length - 1) === ".") {
                    linter.warn("W047", {
                        line: data.line,
                        char: data.char,
                        data: [ data.value ]
                    });
                }

                if (/^00+/.test(data.value)) {
                    linter.warn("W046", {
                        line: data.line,
                        char: data.char,
                        data: [ data.value ]
                    });
                }
            });

            linter.on("String", function style_scanJavaScriptURLs(data) {
                var re = /^(?:javascript|jscript|ecmascript|vbscript|livescript)\s*:/i;

                if (linter.getOption("scripturl")) {
                    return;
                }

                if (re.test(data.value)) {
                    linter.warn("W107", {
                        line: data.line,
                        char: data.char
                    });
                }
            });
        };

    },{}],"/node_modules/jshint/src/vars.js":[function(_dereq_,module,exports){

        "use strict";

        exports.reservedVars = {
            arguments : false,
            NaN       : false
        };

        exports.ecmaIdentifiers = {
            3: {
                Array              : false,
                Boolean            : false,
                Date               : false,
                decodeURI          : false,
                decodeURIComponent : false,
                encodeURI          : false,
                encodeURIComponent : false,
                Error              : false,
                "eval"             : false,
                EvalError          : false,
                Function           : false,
                hasOwnProperty     : false,
                isFinite           : false,
                isNaN              : false,
                Math               : false,
                Number             : false,
                Object             : false,
                parseInt           : false,
                parseFloat         : false,
                RangeError         : false,
                ReferenceError     : false,
                RegExp             : false,
                String             : false,
                SyntaxError        : false,
                TypeError          : false,
                URIError           : false
            },
            5: {
                JSON               : false
            },
            6: {
                Map                : false,
                Promise            : false,
                Proxy              : false,
                Reflect            : false,
                Set                : false,
                Symbol             : false,
                WeakMap            : false,
                WeakSet            : false
            }
        };

        exports.browser = {
            Audio                : false,
            Blob                 : false,
            addEventListener     : false,
            applicationCache     : false,
            atob                 : false,
            blur                 : false,
            btoa                 : false,
            cancelAnimationFrame : false,
            CanvasGradient       : false,
            CanvasPattern        : false,
            CanvasRenderingContext2D: false,
            CSS                  : false,
            clearInterval        : false,
            clearTimeout         : false,
            close                : false,
            closed               : false,
            Comment              : false,
            CustomEvent          : false,
            DOMParser            : false,
            defaultStatus        : false,
            Document             : false,
            document             : false,
            DocumentFragment     : false,
            Element              : false,
            ElementTimeControl   : false,
            Event                : false,
            event                : false,
            fetch                : false,
            FileReader           : false,
            FormData             : false,
            focus                : false,
            frames               : false,
            getComputedStyle     : false,
            HTMLElement          : false,
            HTMLAnchorElement    : false,
            HTMLBaseElement      : false,
            HTMLBlockquoteElement: false,
            HTMLBodyElement      : false,
            HTMLBRElement        : false,
            HTMLButtonElement    : false,
            HTMLCanvasElement    : false,
            HTMLCollection       : false,
            HTMLDirectoryElement : false,
            HTMLDivElement       : false,
            HTMLDListElement     : false,
            HTMLFieldSetElement  : false,
            HTMLFontElement      : false,
            HTMLFormElement      : false,
            HTMLFrameElement     : false,
            HTMLFrameSetElement  : false,
            HTMLHeadElement      : false,
            HTMLHeadingElement   : false,
            HTMLHRElement        : false,
            HTMLHtmlElement      : false,
            HTMLIFrameElement    : false,
            HTMLImageElement     : false,
            HTMLInputElement     : false,
            HTMLIsIndexElement   : false,
            HTMLLabelElement     : false,
            HTMLLayerElement     : false,
            HTMLLegendElement    : false,
            HTMLLIElement        : false,
            HTMLLinkElement      : false,
            HTMLMapElement       : false,
            HTMLMenuElement      : false,
            HTMLMetaElement      : false,
            HTMLModElement       : false,
            HTMLObjectElement    : false,
            HTMLOListElement     : false,
            HTMLOptGroupElement  : false,
            HTMLOptionElement    : false,
            HTMLParagraphElement : false,
            HTMLParamElement     : false,
            HTMLPreElement       : false,
            HTMLQuoteElement     : false,
            HTMLScriptElement    : false,
            HTMLSelectElement    : false,
            HTMLStyleElement     : false,
            HTMLTableCaptionElement: false,
            HTMLTableCellElement : false,
            HTMLTableColElement  : false,
            HTMLTableElement     : false,
            HTMLTableRowElement  : false,
            HTMLTableSectionElement: false,
            HTMLTemplateElement  : false,
            HTMLTextAreaElement  : false,
            HTMLTitleElement     : false,
            HTMLUListElement     : false,
            HTMLVideoElement     : false,
            history              : false,
            Image                : false,
            Intl                 : false,
            length               : false,
            localStorage         : false,
            location             : false,
            matchMedia           : false,
            MessageChannel       : false,
            MessageEvent         : false,
            MessagePort          : false,
            MouseEvent           : false,
            moveBy               : false,
            moveTo               : false,
            MutationObserver     : false,
            name                 : false,
            Node                 : false,
            NodeFilter           : false,
            NodeList             : false,
            Notification         : false,
            navigator            : false,
            onbeforeunload       : true,
            onblur               : true,
            onerror              : true,
            onfocus              : true,
            onload               : true,
            onresize             : true,
            onunload             : true,
            open                 : false,
            openDatabase         : false,
            opener               : false,
            Option               : false,
            parent               : false,
            performance          : false,
            print                : false,
            Range                : false,
            requestAnimationFrame : false,
            removeEventListener  : false,
            resizeBy             : false,
            resizeTo             : false,
            screen               : false,
            scroll               : false,
            scrollBy             : false,
            scrollTo             : false,
            sessionStorage       : false,
            setInterval          : false,
            setTimeout           : false,
            SharedWorker         : false,
            status               : false,
            SVGAElement          : false,
            SVGAltGlyphDefElement: false,
            SVGAltGlyphElement   : false,
            SVGAltGlyphItemElement: false,
            SVGAngle             : false,
            SVGAnimateColorElement: false,
            SVGAnimateElement    : false,
            SVGAnimateMotionElement: false,
            SVGAnimateTransformElement: false,
            SVGAnimatedAngle     : false,
            SVGAnimatedBoolean   : false,
            SVGAnimatedEnumeration: false,
            SVGAnimatedInteger   : false,
            SVGAnimatedLength    : false,
            SVGAnimatedLengthList: false,
            SVGAnimatedNumber    : false,
            SVGAnimatedNumberList: false,
            SVGAnimatedPathData  : false,
            SVGAnimatedPoints    : false,
            SVGAnimatedPreserveAspectRatio: false,
            SVGAnimatedRect      : false,
            SVGAnimatedString    : false,
            SVGAnimatedTransformList: false,
            SVGAnimationElement  : false,
            SVGCSSRule           : false,
            SVGCircleElement     : false,
            SVGClipPathElement   : false,
            SVGColor             : false,
            SVGColorProfileElement: false,
            SVGColorProfileRule  : false,
            SVGComponentTransferFunctionElement: false,
            SVGCursorElement     : false,
            SVGDefsElement       : false,
            SVGDescElement       : false,
            SVGDocument          : false,
            SVGElement           : false,
            SVGElementInstance   : false,
            SVGElementInstanceList: false,
            SVGEllipseElement    : false,
            SVGExternalResourcesRequired: false,
            SVGFEBlendElement    : false,
            SVGFEColorMatrixElement: false,
            SVGFEComponentTransferElement: false,
            SVGFECompositeElement: false,
            SVGFEConvolveMatrixElement: false,
            SVGFEDiffuseLightingElement: false,
            SVGFEDisplacementMapElement: false,
            SVGFEDistantLightElement: false,
            SVGFEFloodElement    : false,
            SVGFEFuncAElement    : false,
            SVGFEFuncBElement    : false,
            SVGFEFuncGElement    : false,
            SVGFEFuncRElement    : false,
            SVGFEGaussianBlurElement: false,
            SVGFEImageElement    : false,
            SVGFEMergeElement    : false,
            SVGFEMergeNodeElement: false,
            SVGFEMorphologyElement: false,
            SVGFEOffsetElement   : false,
            SVGFEPointLightElement: false,
            SVGFESpecularLightingElement: false,
            SVGFESpotLightElement: false,
            SVGFETileElement     : false,
            SVGFETurbulenceElement: false,
            SVGFilterElement     : false,
            SVGFilterPrimitiveStandardAttributes: false,
            SVGFitToViewBox      : false,
            SVGFontElement       : false,
            SVGFontFaceElement   : false,
            SVGFontFaceFormatElement: false,
            SVGFontFaceNameElement: false,
            SVGFontFaceSrcElement: false,
            SVGFontFaceUriElement: false,
            SVGForeignObjectElement: false,
            SVGGElement          : false,
            SVGGlyphElement      : false,
            SVGGlyphRefElement   : false,
            SVGGradientElement   : false,
            SVGHKernElement      : false,
            SVGICCColor          : false,
            SVGImageElement      : false,
            SVGLangSpace         : false,
            SVGLength            : false,
            SVGLengthList        : false,
            SVGLineElement       : false,
            SVGLinearGradientElement: false,
            SVGLocatable         : false,
            SVGMPathElement      : false,
            SVGMarkerElement     : false,
            SVGMaskElement       : false,
            SVGMatrix            : false,
            SVGMetadataElement   : false,
            SVGMissingGlyphElement: false,
            SVGNumber            : false,
            SVGNumberList        : false,
            SVGPaint             : false,
            SVGPathElement       : false,
            SVGPathSeg           : false,
            SVGPathSegArcAbs     : false,
            SVGPathSegArcRel     : false,
            SVGPathSegClosePath  : false,
            SVGPathSegCurvetoCubicAbs: false,
            SVGPathSegCurvetoCubicRel: false,
            SVGPathSegCurvetoCubicSmoothAbs: false,
            SVGPathSegCurvetoCubicSmoothRel: false,
            SVGPathSegCurvetoQuadraticAbs: false,
            SVGPathSegCurvetoQuadraticRel: false,
            SVGPathSegCurvetoQuadraticSmoothAbs: false,
            SVGPathSegCurvetoQuadraticSmoothRel: false,
            SVGPathSegLinetoAbs  : false,
            SVGPathSegLinetoHorizontalAbs: false,
            SVGPathSegLinetoHorizontalRel: false,
            SVGPathSegLinetoRel  : false,
            SVGPathSegLinetoVerticalAbs: false,
            SVGPathSegLinetoVerticalRel: false,
            SVGPathSegList       : false,
            SVGPathSegMovetoAbs  : false,
            SVGPathSegMovetoRel  : false,
            SVGPatternElement    : false,
            SVGPoint             : false,
            SVGPointList         : false,
            SVGPolygonElement    : false,
            SVGPolylineElement   : false,
            SVGPreserveAspectRatio: false,
            SVGRadialGradientElement: false,
            SVGRect              : false,
            SVGRectElement       : false,
            SVGRenderingIntent   : false,
            SVGSVGElement        : false,
            SVGScriptElement     : false,
            SVGSetElement        : false,
            SVGStopElement       : false,
            SVGStringList        : false,
            SVGStylable          : false,
            SVGStyleElement      : false,
            SVGSwitchElement     : false,
            SVGSymbolElement     : false,
            SVGTRefElement       : false,
            SVGTSpanElement      : false,
            SVGTests             : false,
            SVGTextContentElement: false,
            SVGTextElement       : false,
            SVGTextPathElement   : false,
            SVGTextPositioningElement: false,
            SVGTitleElement      : false,
            SVGTransform         : false,
            SVGTransformList     : false,
            SVGTransformable     : false,
            SVGURIReference      : false,
            SVGUnitTypes         : false,
            SVGUseElement        : false,
            SVGVKernElement      : false,
            SVGViewElement       : false,
            SVGViewSpec          : false,
            SVGZoomAndPan        : false,
            Text                 : false,
            TextDecoder          : false,
            TextEncoder          : false,
            TimeEvent            : false,
            top                  : false,
            URL                  : false,
            WebGLActiveInfo      : false,
            WebGLBuffer          : false,
            WebGLContextEvent    : false,
            WebGLFramebuffer     : false,
            WebGLProgram         : false,
            WebGLRenderbuffer    : false,
            WebGLRenderingContext: false,
            WebGLShader          : false,
            WebGLShaderPrecisionFormat: false,
            WebGLTexture         : false,
            WebGLUniformLocation : false,
            WebSocket            : false,
            window               : false,
            Window               : false,
            Worker               : false,
            XDomainRequest       : false,
            XMLHttpRequest       : false,
            XMLSerializer        : false,
            XPathEvaluator       : false,
            XPathException       : false,
            XPathExpression      : false,
            XPathNamespace       : false,
            XPathNSResolver      : false,
            XPathResult          : false
        };

        exports.devel = {
            alert  : false,
            confirm: false,
            console: false,
            Debug  : false,
            opera  : false,
            prompt : false
        };

        exports.worker = {
            importScripts  : true,
            postMessage    : true,
            self           : true,
            FileReaderSync : true
        };
        exports.nonstandard = {
            escape  : false,
            unescape: false
        };

        exports.couch = {
            "require" : false,
            respond   : false,
            getRow    : false,
            emit      : false,
            send      : false,
            start     : false,
            sum       : false,
            log       : false,
            exports   : false,
            module    : false,
            provides  : false
        };

        exports.node = {
            __filename    : false,
            __dirname     : false,
            GLOBAL        : false,
            global        : false,
            module        : false,
            require       : false,

            Buffer        : true,
            console       : true,
            exports       : true,
            process       : true,
            setTimeout    : true,
            clearTimeout  : true,
            setInterval   : true,
            clearInterval : true,
            setImmediate  : true, // v0.9.1+
            clearImmediate: true  // v0.9.1+
        };

        exports.browserify = {
            __filename    : false,
            __dirname     : false,
            global        : false,
            module        : false,
            require       : false,
            Buffer        : true,
            exports       : true,
            process       : true
        };

        exports.phantom = {
            phantom      : true,
            require      : true,
            WebPage      : true,
            console      : true, // in examples, but undocumented
            exports      : true  // v1.7+
        };

        exports.qunit = {
            asyncTest      : false,
            deepEqual      : false,
            equal          : false,
            expect         : false,
            module         : false,
            notDeepEqual   : false,
            notEqual       : false,
            notPropEqual   : false,
            notStrictEqual : false,
            ok             : false,
            propEqual      : false,
            QUnit          : false,
            raises         : false,
            start          : false,
            stop           : false,
            strictEqual    : false,
            test           : false,
            "throws"       : false
        };

        exports.rhino = {
            defineClass  : false,
            deserialize  : false,
            gc           : false,
            help         : false,
            importClass  : false,
            importPackage: false,
            "java"       : false,
            load         : false,
            loadClass    : false,
            Packages     : false,
            print        : false,
            quit         : false,
            readFile     : false,
            readUrl      : false,
            runCommand   : false,
            seal         : false,
            serialize    : false,
            spawn        : false,
            sync         : false,
            toint32      : false,
            version      : false
        };

        exports.shelljs = {
            target       : false,
            echo         : false,
            exit         : false,
            cd           : false,
            pwd          : false,
            ls           : false,
            find         : false,
            cp           : false,
            rm           : false,
            mv           : false,
            mkdir        : false,
            test         : false,
            cat          : false,
            sed          : false,
            grep         : false,
            which        : false,
            dirs         : false,
            pushd        : false,
            popd         : false,
            env          : false,
            exec         : false,
            chmod        : false,
            config       : false,
            error        : false,
            tempdir      : false
        };

        exports.typed = {
            ArrayBuffer         : false,
            ArrayBufferView     : false,
            DataView            : false,
            Float32Array        : false,
            Float64Array        : false,
            Int16Array          : false,
            Int32Array          : false,
            Int8Array           : false,
            Uint16Array         : false,
            Uint32Array         : false,
            Uint8Array          : false,
            Uint8ClampedArray   : false
        };

        exports.wsh = {
            ActiveXObject            : true,
            Enumerator               : true,
            GetObject                : true,
            ScriptEngine             : true,
            ScriptEngineBuildVersion : true,
            ScriptEngineMajorVersion : true,
            ScriptEngineMinorVersion : true,
            VBArray                  : true,
            WSH                      : true,
            WScript                  : true,
            XDomainRequest           : true
        };

        exports.dojo = {
            dojo     : false,
            dijit    : false,
            dojox    : false,
            define   : false,
            "require": false
        };

        exports.jquery = {
            "$"    : false,
            jQuery : false
        };

        exports.mootools = {
            "$"           : false,
            "$$"          : false,
            Asset         : false,
            Browser       : false,
            Chain         : false,
            Class         : false,
            Color         : false,
            Cookie        : false,
            Core          : false,
            Document      : false,
            DomReady      : false,
            DOMEvent      : false,
            DOMReady      : false,
            Drag          : false,
            Element       : false,
            Elements      : false,
            Event         : false,
            Events        : false,
            Fx            : false,
            Group         : false,
            Hash          : false,
            HtmlTable     : false,
            IFrame        : false,
            IframeShim    : false,
            InputValidator: false,
            instanceOf    : false,
            Keyboard      : false,
            Locale        : false,
            Mask          : false,
            MooTools      : false,
            Native        : false,
            Options       : false,
            OverText      : false,
            Request       : false,
            Scroller      : false,
            Slick         : false,
            Slider        : false,
            Sortables     : false,
            Spinner       : false,
            Swiff         : false,
            Tips          : false,
            Type          : false,
            typeOf        : false,
            URI           : false,
            Window        : false
        };

        exports.prototypejs = {
            "$"               : false,
            "$$"              : false,
            "$A"              : false,
            "$F"              : false,
            "$H"              : false,
            "$R"              : false,
            "$break"          : false,
            "$continue"       : false,
            "$w"              : false,
            Abstract          : false,
            Ajax              : false,
            Class             : false,
            Enumerable        : false,
            Element           : false,
            Event             : false,
            Field             : false,
            Form              : false,
            Hash              : false,
            Insertion         : false,
            ObjectRange       : false,
            PeriodicalExecuter: false,
            Position          : false,
            Prototype         : false,
            Selector          : false,
            Template          : false,
            Toggle            : false,
            Try               : false,
            Autocompleter     : false,
            Builder           : false,
            Control           : false,
            Draggable         : false,
            Draggables        : false,
            Droppables        : false,
            Effect            : false,
            Sortable          : false,
            SortableObserver  : false,
            Sound             : false,
            Scriptaculous     : false
        };

        exports.yui = {
            YUI       : false,
            Y         : false,
            YUI_config: false
        };

        exports.mocha = {
            mocha       : false,
            describe    : false,
            xdescribe   : false,
            it          : false,
            xit         : false,
            context     : false,
            xcontext    : false,
            before      : false,
            after       : false,
            beforeEach  : false,
            afterEach   : false,
            suite         : false,
            test          : false,
            setup         : false,
            teardown      : false,
            suiteSetup    : false,
            suiteTeardown : false
        };

        exports.jasmine = {
            jasmine     : false,
            describe    : false,
            xdescribe   : false,
            it          : false,
            xit         : false,
            beforeEach  : false,
            afterEach   : false,
            setFixtures : false,
            loadFixtures: false,
            spyOn       : false,
            expect      : false,
            runs        : false,
            waitsFor    : false,
            waits       : false,
            beforeAll   : false,
            afterAll    : false,
            fail        : false,
            fdescribe   : false,
            fit         : false,
            pending     : false
        };

    },{}]},{},["/node_modules/jshint/src/jshint.js"]);

});

ace.define("ace/mode/javascript_worker",["require","exports","module","ace/lib/oop","ace/worker/mirror","ace/mode/javascript/jshint"], function(require, exports, module) {
    "use strict";

    var oop = require("../lib/oop");
    var Mirror = require("../worker/mirror").Mirror;
    var lint = require("./javascript/jshint").JSHINT;

    function startRegex(arr) {
        return RegExp("^(" + arr.join("|") + ")");
    }

    var disabledWarningsRe = startRegex([
        "Bad for in variable '(.+)'.",
        'Missing "use strict"'
    ]);
    var errorsRe = startRegex([
        "Unexpected",
        "Expected ",
        "Confusing (plus|minus)",
        "\\{a\\} unterminated regular expression",
        "Unclosed ",
        "Unmatched ",
        "Unbegun comment",
        "Bad invocation",
        "Missing space after",
        "Missing operator at"
    ]);
    var infoRe = startRegex([
        "Expected an assignment",
        "Bad escapement of EOL",
        "Unexpected comma",
        "Unexpected space",
        "Missing radix parameter.",
        "A leading decimal point can",
        "\\['{a}'\\] is better written in dot notation.",
        "'{a}' used out of scope"
    ]);

    var JavaScriptWorker = exports.JavaScriptWorker = function(sender) {
        Mirror.call(this, sender);
        this.setTimeout(500);
        this.setOptions();
    };

    oop.inherits(JavaScriptWorker, Mirror);

    (function() {
        this.setOptions = function(options) {
            this.options = options || {
                    esnext: true,
                    moz: true,
                    devel: true,
                    browser: true,
                    node: true,
                    laxcomma: true,
                    laxbreak: true,
                    lastsemic: true,
                    onevar: false,
                    passfail: false,
                    maxerr: 100,
                    expr: true,
                    multistr: true,
                    globalstrict: true
                };
            this.doc.getValue() && this.deferredUpdate.schedule(100);
        };

        this.changeOptions = function(newOptions) {
            oop.mixin(this.options, newOptions);
            this.doc.getValue() && this.deferredUpdate.schedule(100);
        };

        this.isValidJS = function(str) {
            try {
                eval("throw 0;" + str);
            } catch(e) {
                if (e === 0)
                    return true;
            }
            return false
        };

        this.onUpdate = function() {
            var value = this.doc.getValue();
            value = value.replace(/^#!.*\n/, "\n");
            if (!value)
                return this.sender.emit("annotate", []);

            var errors = [];
            var maxErrorLevel = this.isValidJS(value) ? "warning" : "error";
            lint(value, this.options, this.options.globals);
            var results = lint.errors;

            var errorAdded = false
            for (var i = 0; i < results.length; i++) {
                var error = results[i];
                if (!error)
                    continue;
                var raw = error.raw;
                var type = "warning";

                if (raw == "Missing semicolon.") {
                    var str = error.evidence.substr(error.character);
                    str = str.charAt(str.search(/\S/));
                    if (maxErrorLevel == "error" && str && /[\w\d{(['"]/.test(str)) {
                        error.reason = 'Missing ";" before statement';
                        type = "error";
                    } else {
                        type = "info";
                    }
                }
                else if (disabledWarningsRe.test(raw)) {
                    continue;
                }
                else if (infoRe.test(raw)) {
                    type = "info"
                }
                else if (errorsRe.test(raw)) {
                    errorAdded  = true;
                    type = maxErrorLevel;
                }
                else if (raw == "'{a}' is not defined.") {
                    type = "warning";
                }
                else if (raw == "'{a}' is defined but never used.") {
                    type = "info";
                }

                errors.push({
                    row: error.line-1,
                    column: error.character-1,
                    text: error.reason,
                    type: type,
                    raw: raw
                });

                if (errorAdded) {
                }
            }

            this.sender.emit("annotate", errors);
        };

    }).call(JavaScriptWorker.prototype);

});

ace.define("ace/lib/es5-shim",["require","exports","module"], function(require, exports, module) {

    function Empty() {}

    if (!Function.prototype.bind) {
        Function.prototype.bind = function bind(that) { // .length is 1
            var target = this;
            if (typeof target != "function") {
                throw new TypeError("Function.prototype.bind called on incompatible " + target);
            }
            var args = slice.call(arguments, 1); // for normal call
            var bound = function () {

                if (this instanceof bound) {

                    var result = target.apply(
                        this,
                        args.concat(slice.call(arguments))
                    );
                    if (Object(result) === result) {
                        return result;
                    }
                    return this;

                } else {
                    return target.apply(
                        that,
                        args.concat(slice.call(arguments))
                    );

                }

            };
            if(target.prototype) {
                Empty.prototype = target.prototype;
                bound.prototype = new Empty();
                Empty.prototype = null;
            }
            return bound;
        };
    }
    var call = Function.prototype.call;
    var prototypeOfArray = Array.prototype;
    var prototypeOfObject = Object.prototype;
    var slice = prototypeOfArray.slice;
    var _toString = call.bind(prototypeOfObject.toString);
    var owns = call.bind(prototypeOfObject.hasOwnProperty);
    var defineGetter;
    var defineSetter;
    var lookupGetter;
    var lookupSetter;
    var supportsAccessors;
    if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
        defineGetter = call.bind(prototypeOfObject.__defineGetter__);
        defineSetter = call.bind(prototypeOfObject.__defineSetter__);
        lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
        lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
    }
    if ([1,2].splice(0).length != 2) {
        if(function() { // test IE < 9 to splice bug - see issue #138
                function makeArray(l) {
                    var a = new Array(l+2);
                    a[0] = a[1] = 0;
                    return a;
                }
                var array = [], lengthBefore;

                array.splice.apply(array, makeArray(20));
                array.splice.apply(array, makeArray(26));

                lengthBefore = array.length; //46
                array.splice(5, 0, "XXX"); // add one element

                lengthBefore + 1 == array.length

                if (lengthBefore + 1 == array.length) {
                    return true;// has right splice implementation without bugs
                }
            }()) {//IE 6/7
            var array_splice = Array.prototype.splice;
            Array.prototype.splice = function(start, deleteCount) {
                if (!arguments.length) {
                    return [];
                } else {
                    return array_splice.apply(this, [
                        start === void 0 ? 0 : start,
                        deleteCount === void 0 ? (this.length - start) : deleteCount
                    ].concat(slice.call(arguments, 2)))
                }
            };
        } else {//IE8
            Array.prototype.splice = function(pos, removeCount){
                var length = this.length;
                if (pos > 0) {
                    if (pos > length)
                        pos = length;
                } else if (pos == void 0) {
                    pos = 0;
                } else if (pos < 0) {
                    pos = Math.max(length + pos, 0);
                }

                if (!(pos+removeCount < length))
                    removeCount = length - pos;

                var removed = this.slice(pos, pos+removeCount);
                var insert = slice.call(arguments, 2);
                var add = insert.length;
                if (pos === length) {
                    if (add) {
                        this.push.apply(this, insert);
                    }
                } else {
                    var remove = Math.min(removeCount, length - pos);
                    var tailOldPos = pos + remove;
                    var tailNewPos = tailOldPos + add - remove;
                    var tailCount = length - tailOldPos;
                    var lengthAfterRemove = length - remove;

                    if (tailNewPos < tailOldPos) { // case A
                        for (var i = 0; i < tailCount; ++i) {
                            this[tailNewPos+i] = this[tailOldPos+i];
                        }
                    } else if (tailNewPos > tailOldPos) { // case B
                        for (i = tailCount; i--; ) {
                            this[tailNewPos+i] = this[tailOldPos+i];
                        }
                    } // else, add == remove (nothing to do)

                    if (add && pos === lengthAfterRemove) {
                        this.length = lengthAfterRemove; // truncate array
                        this.push.apply(this, insert);
                    } else {
                        this.length = lengthAfterRemove + add; // reserves space
                        for (i = 0; i < add; ++i) {
                            this[pos+i] = insert[i];
                        }
                    }
                }
                return removed;
            };
        }
    }
    if (!Array.isArray) {
        Array.isArray = function isArray(obj) {
            return _toString(obj) == "[object Array]";
        };
    }
    var boxedString = Object("a"),
        splitString = boxedString[0] != "a" || !(0 in boxedString);

    if (!Array.prototype.forEach) {
        Array.prototype.forEach = function forEach(fun /*, thisp*/) {
            var object = toObject(this),
                self = splitString && _toString(this) == "[object String]" ?
                    this.split("") :
                    object,
                thisp = arguments[1],
                i = -1,
                length = self.length >>> 0;
            if (_toString(fun) != "[object Function]") {
                throw new TypeError(); // TODO message
            }

            while (++i < length) {
                if (i in self) {
                    fun.call(thisp, self[i], i, object);
                }
            }
        };
    }
    if (!Array.prototype.map) {
        Array.prototype.map = function map(fun /*, thisp*/) {
            var object = toObject(this),
                self = splitString && _toString(this) == "[object String]" ?
                    this.split("") :
                    object,
                length = self.length >>> 0,
                result = Array(length),
                thisp = arguments[1];
            if (_toString(fun) != "[object Function]") {
                throw new TypeError(fun + " is not a function");
            }

            for (var i = 0; i < length; i++) {
                if (i in self)
                    result[i] = fun.call(thisp, self[i], i, object);
            }
            return result;
        };
    }
    if (!Array.prototype.filter) {
        Array.prototype.filter = function filter(fun /*, thisp */) {
            var object = toObject(this),
                self = splitString && _toString(this) == "[object String]" ?
                    this.split("") :
                    object,
                length = self.length >>> 0,
                result = [],
                value,
                thisp = arguments[1];
            if (_toString(fun) != "[object Function]") {
                throw new TypeError(fun + " is not a function");
            }

            for (var i = 0; i < length; i++) {
                if (i in self) {
                    value = self[i];
                    if (fun.call(thisp, value, i, object)) {
                        result.push(value);
                    }
                }
            }
            return result;
        };
    }
    if (!Array.prototype.every) {
        Array.prototype.every = function every(fun /*, thisp */) {
            var object = toObject(this),
                self = splitString && _toString(this) == "[object String]" ?
                    this.split("") :
                    object,
                length = self.length >>> 0,
                thisp = arguments[1];
            if (_toString(fun) != "[object Function]") {
                throw new TypeError(fun + " is not a function");
            }

            for (var i = 0; i < length; i++) {
                if (i in self && !fun.call(thisp, self[i], i, object)) {
                    return false;
                }
            }
            return true;
        };
    }
    if (!Array.prototype.some) {
        Array.prototype.some = function some(fun /*, thisp */) {
            var object = toObject(this),
                self = splitString && _toString(this) == "[object String]" ?
                    this.split("") :
                    object,
                length = self.length >>> 0,
                thisp = arguments[1];
            if (_toString(fun) != "[object Function]") {
                throw new TypeError(fun + " is not a function");
            }

            for (var i = 0; i < length; i++) {
                if (i in self && fun.call(thisp, self[i], i, object)) {
                    return true;
                }
            }
            return false;
        };
    }
    if (!Array.prototype.reduce) {
        Array.prototype.reduce = function reduce(fun /*, initial*/) {
            var object = toObject(this),
                self = splitString && _toString(this) == "[object String]" ?
                    this.split("") :
                    object,
                length = self.length >>> 0;
            if (_toString(fun) != "[object Function]") {
                throw new TypeError(fun + " is not a function");
            }
            if (!length && arguments.length == 1) {
                throw new TypeError("reduce of empty array with no initial value");
            }

            var i = 0;
            var result;
            if (arguments.length >= 2) {
                result = arguments[1];
            } else {
                do {
                    if (i in self) {
                        result = self[i++];
                        break;
                    }
                    if (++i >= length) {
                        throw new TypeError("reduce of empty array with no initial value");
                    }
                } while (true);
            }

            for (; i < length; i++) {
                if (i in self) {
                    result = fun.call(void 0, result, self[i], i, object);
                }
            }

            return result;
        };
    }
    if (!Array.prototype.reduceRight) {
        Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
            var object = toObject(this),
                self = splitString && _toString(this) == "[object String]" ?
                    this.split("") :
                    object,
                length = self.length >>> 0;
            if (_toString(fun) != "[object Function]") {
                throw new TypeError(fun + " is not a function");
            }
            if (!length && arguments.length == 1) {
                throw new TypeError("reduceRight of empty array with no initial value");
            }

            var result, i = length - 1;
            if (arguments.length >= 2) {
                result = arguments[1];
            } else {
                do {
                    if (i in self) {
                        result = self[i--];
                        break;
                    }
                    if (--i < 0) {
                        throw new TypeError("reduceRight of empty array with no initial value");
                    }
                } while (true);
            }

            do {
                if (i in this) {
                    result = fun.call(void 0, result, self[i], i, object);
                }
            } while (i--);

            return result;
        };
    }
    if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) {
        Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
            var self = splitString && _toString(this) == "[object String]" ?
                    this.split("") :
                    toObject(this),
                length = self.length >>> 0;

            if (!length) {
                return -1;
            }

            var i = 0;
            if (arguments.length > 1) {
                i = toInteger(arguments[1]);
            }
            i = i >= 0 ? i : Math.max(0, length + i);
            for (; i < length; i++) {
                if (i in self && self[i] === sought) {
                    return i;
                }
            }
            return -1;
        };
    }
    if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) {
        Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
            var self = splitString && _toString(this) == "[object String]" ?
                    this.split("") :
                    toObject(this),
                length = self.length >>> 0;

            if (!length) {
                return -1;
            }
            var i = length - 1;
            if (arguments.length > 1) {
                i = Math.min(i, toInteger(arguments[1]));
            }
            i = i >= 0 ? i : length - Math.abs(i);
            for (; i >= 0; i--) {
                if (i in self && sought === self[i]) {
                    return i;
                }
            }
            return -1;
        };
    }
    if (!Object.getPrototypeOf) {
        Object.getPrototypeOf = function getPrototypeOf(object) {
            return object.__proto__ || (
                    object.constructor ?
                        object.constructor.prototype :
                        prototypeOfObject
                );
        };
    }
    if (!Object.getOwnPropertyDescriptor) {
        var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a " +
            "non-object: ";
        Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) {
            if ((typeof object != "object" && typeof object != "function") || object === null)
                throw new TypeError(ERR_NON_OBJECT + object);
            if (!owns(object, property))
                return;

            var descriptor, getter, setter;
            descriptor =  { enumerable: true, configurable: true };
            if (supportsAccessors) {
                var prototype = object.__proto__;
                object.__proto__ = prototypeOfObject;

                var getter = lookupGetter(object, property);
                var setter = lookupSetter(object, property);
                object.__proto__ = prototype;

                if (getter || setter) {
                    if (getter) descriptor.get = getter;
                    if (setter) descriptor.set = setter;
                    return descriptor;
                }
            }
            descriptor.value = object[property];
            return descriptor;
        };
    }
    if (!Object.getOwnPropertyNames) {
        Object.getOwnPropertyNames = function getOwnPropertyNames(object) {
            return Object.keys(object);
        };
    }
    if (!Object.create) {
        var createEmpty;
        if (Object.prototype.__proto__ === null) {
            createEmpty = function () {
                return { "__proto__": null };
            };
        } else {
            createEmpty = function () {
                var empty = {};
                for (var i in empty)
                    empty[i] = null;
                empty.constructor =
                    empty.hasOwnProperty =
                        empty.propertyIsEnumerable =
                            empty.isPrototypeOf =
                                empty.toLocaleString =
                                    empty.toString =
                                        empty.valueOf =
                                            empty.__proto__ = null;
                return empty;
            }
        }

        Object.create = function create(prototype, properties) {
            var object;
            if (prototype === null) {
                object = createEmpty();
            } else {
                if (typeof prototype != "object")
                    throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");
                var Type = function () {};
                Type.prototype = prototype;
                object = new Type();
                object.__proto__ = prototype;
            }
            if (properties !== void 0)
                Object.defineProperties(object, properties);
            return object;
        };
    }

    function doesDefinePropertyWork(object) {
        try {
            Object.defineProperty(object, "sentinel", {});
            return "sentinel" in object;
        } catch (exception) {
        }
    }
    if (Object.defineProperty) {
        var definePropertyWorksOnObject = doesDefinePropertyWork({});
        var definePropertyWorksOnDom = typeof document == "undefined" ||
            doesDefinePropertyWork(document.createElement("div"));
        if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {
            var definePropertyFallback = Object.defineProperty;
        }
    }

    if (!Object.defineProperty || definePropertyFallback) {
        var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";
        var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "
        var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +
            "on this javascript engine";

        Object.defineProperty = function defineProperty(object, property, descriptor) {
            if ((typeof object != "object" && typeof object != "function") || object === null)
                throw new TypeError(ERR_NON_OBJECT_TARGET + object);
            if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null)
                throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);
            if (definePropertyFallback) {
                try {
                    return definePropertyFallback.call(Object, object, property, descriptor);
                } catch (exception) {
                }
            }
            if (owns(descriptor, "value")) {

                if (supportsAccessors && (lookupGetter(object, property) ||
                    lookupSetter(object, property)))
                {
                    var prototype = object.__proto__;
                    object.__proto__ = prototypeOfObject;
                    delete object[property];
                    object[property] = descriptor.value;
                    object.__proto__ = prototype;
                } else {
                    object[property] = descriptor.value;
                }
            } else {
                if (!supportsAccessors)
                    throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);
                if (owns(descriptor, "get"))
                    defineGetter(object, property, descriptor.get);
                if (owns(descriptor, "set"))
                    defineSetter(object, property, descriptor.set);
            }

            return object;
        };
    }
    if (!Object.defineProperties) {
        Object.defineProperties = function defineProperties(object, properties) {
            for (var property in properties) {
                if (owns(properties, property))
                    Object.defineProperty(object, property, properties[property]);
            }
            return object;
        };
    }
    if (!Object.seal) {
        Object.seal = function seal(object) {
            return object;
        };
    }
    if (!Object.freeze) {
        Object.freeze = function freeze(object) {
            return object;
        };
    }
    try {
        Object.freeze(function () {});
    } catch (exception) {
        Object.freeze = (function freeze(freezeObject) {
            return function freeze(object) {
                if (typeof object == "function") {
                    return object;
                } else {
                    return freezeObject(object);
                }
            };
        })(Object.freeze);
    }
    if (!Object.preventExtensions) {
        Object.preventExtensions = function preventExtensions(object) {
            return object;
        };
    }
    if (!Object.isSealed) {
        Object.isSealed = function isSealed(object) {
            return false;
        };
    }
    if (!Object.isFrozen) {
        Object.isFrozen = function isFrozen(object) {
            return false;
        };
    }
    if (!Object.isExtensible) {
        Object.isExtensible = function isExtensible(object) {
            if (Object(object) === object) {
                throw new TypeError(); // TODO message
            }
            var name = '';
            while (owns(object, name)) {
                name += '?';
            }
            object[name] = true;
            var returnValue = owns(object, name);
            delete object[name];
            return returnValue;
        };
    }
    if (!Object.keys) {
        var hasDontEnumBug = true,
            dontEnums = [
                "toString",
                "toLocaleString",
                "valueOf",
                "hasOwnProperty",
                "isPrototypeOf",
                "propertyIsEnumerable",
                "constructor"
            ],
            dontEnumsLength = dontEnums.length;

        for (var key in {"toString": null}) {
            hasDontEnumBug = false;
        }

        Object.keys = function keys(object) {

            if (
                (typeof object != "object" && typeof object != "function") ||
                object === null
            ) {
                throw new TypeError("Object.keys called on a non-object");
            }

            var keys = [];
            for (var name in object) {
                if (owns(object, name)) {
                    keys.push(name);
                }
            }

            if (hasDontEnumBug) {
                for (var i = 0, ii = dontEnumsLength; i < ii; i++) {
                    var dontEnum = dontEnums[i];
                    if (owns(object, dontEnum)) {
                        keys.push(dontEnum);
                    }
                }
            }
            return keys;
        };

    }
    if (!Date.now) {
        Date.now = function now() {
            return new Date().getTime();
        };
    }
    var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
        "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
        "\u2029\uFEFF";
    if (!String.prototype.trim || ws.trim()) {
        ws = "[" + ws + "]";
        var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
            trimEndRegexp = new RegExp(ws + ws + "*$");
        String.prototype.trim = function trim() {
            return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
        };
    }

    function toInteger(n) {
        n = +n;
        if (n !== n) { // isNaN
            n = 0;
        } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
            n = (n > 0 || -1) * Math.floor(Math.abs(n));
        }
        return n;
    }

    function isPrimitive(input) {
        var type = typeof input;
        return (
            input === null ||
            type === "undefined" ||
            type === "boolean" ||
            type === "number" ||
            type === "string"
        );
    }

    function toPrimitive(input) {
        var val, valueOf, toString;
        if (isPrimitive(input)) {
            return input;
        }
        valueOf = input.valueOf;
        if (typeof valueOf === "function") {
            val = valueOf.call(input);
            if (isPrimitive(val)) {
                return val;
            }
        }
        toString = input.toString;
        if (typeof toString === "function") {
            val = toString.call(input);
            if (isPrimitive(val)) {
                return val;
            }
        }
        throw new TypeError();
    }
    var toObject = function (o) {
        if (o == null) { // this matches both null and undefined
            throw new TypeError("can't convert "+o+" to object");
        }
        return Object(o);
    };

});